OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 2009 Apple Inc. All rights reserved. | 2 * Copyright (C) 2009 Apple Inc. All rights reserved. |
3 * | 3 * |
4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
5 * modification, are permitted provided that the following conditions | 5 * modification, are permitted provided that the following conditions |
6 * are met: | 6 * are met: |
7 * 1. Redistributions of source code must retain the above copyright | 7 * 1. Redistributions of source code must retain the above copyright |
8 * notice, this list of conditions and the following disclaimer. | 8 * notice, this list of conditions and the following disclaimer. |
9 * 2. Redistributions in binary form must reproduce the above copyright | 9 * 2. Redistributions in binary form must reproduce the above copyright |
10 * notice, this list of conditions and the following disclaimer in the | 10 * notice, this list of conditions and the following disclaimer in the |
(...skipping 204 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
215 if (!desiredSize.isEmpty()) { | 215 if (!desiredSize.isEmpty()) { |
216 forciblyEvictedContexts().remove(0); | 216 forciblyEvictedContexts().remove(0); |
217 evictedContext->forceRestoreContext(); | 217 evictedContext->forceRestoreContext(); |
218 } | 218 } |
219 break; | 219 break; |
220 } | 220 } |
221 } | 221 } |
222 | 222 |
223 namespace { | 223 namespace { |
224 | 224 |
225 // ScopedDrawingBufferBinder is used for ReadPixels/CopyTexImage2D/CopySubIm
age2D to read from | 225 // ScopedDrawingBufferBinder is used for ReadPixels/CopyTexImage2D/CopySubImage2
D to read from |
226 // a multisampled DrawingBuffer. In this situation, we need to blit to a sin
gle sampled buffer | 226 // a multisampled DrawingBuffer. In this situation, we need to blit to a single
sampled buffer |
227 // for reading, during which the bindings could be changed and need to be re
covered. | 227 // for reading, during which the bindings could be changed and need to be recove
red. |
228 class ScopedDrawingBufferBinder { | 228 class ScopedDrawingBufferBinder { |
229 STACK_ALLOCATED(); | 229 STACK_ALLOCATED(); |
230 public: | 230 public: |
231 ScopedDrawingBufferBinder(DrawingBuffer* drawingBuffer, WebGLFramebuffer
* framebufferBinding) | 231 ScopedDrawingBufferBinder(DrawingBuffer* drawingBuffer, WebGLFramebuffer* fr
amebufferBinding) |
232 : m_drawingBuffer(drawingBuffer) | 232 : m_drawingBuffer(drawingBuffer) |
233 , m_readFramebufferBinding(framebufferBinding) | 233 , m_readFramebufferBinding(framebufferBinding) |
234 { | 234 { |
235 // Commit DrawingBuffer if needed (e.g., for multisampling) | 235 // Commit DrawingBuffer if needed (e.g., for multisampling) |
236 if (!m_readFramebufferBinding && m_drawingBuffer) | 236 if (!m_readFramebufferBinding && m_drawingBuffer) |
237 m_drawingBuffer->commit(); | 237 m_drawingBuffer->commit(); |
238 } | 238 } |
239 | 239 |
240 ~ScopedDrawingBufferBinder() | 240 ~ScopedDrawingBufferBinder() |
241 { | 241 { |
242 // Restore DrawingBuffer if needed | 242 // Restore DrawingBuffer if needed |
243 if (!m_readFramebufferBinding && m_drawingBuffer) | 243 if (!m_readFramebufferBinding && m_drawingBuffer) |
244 m_drawingBuffer->restoreFramebufferBindings(); | 244 m_drawingBuffer->restoreFramebufferBindings(); |
245 } | 245 } |
246 | 246 |
247 private: | 247 private: |
248 DrawingBuffer* m_drawingBuffer; | 248 DrawingBuffer* m_drawingBuffer; |
249 RawPtrWillBeMember<WebGLFramebuffer> m_readFramebufferBinding; | 249 RawPtrWillBeMember<WebGLFramebuffer> m_readFramebufferBinding; |
| 250 }; |
| 251 |
| 252 GLint clamp(GLint value, GLint min, GLint max) |
| 253 { |
| 254 if (value < min) |
| 255 value = min; |
| 256 if (value > max) |
| 257 value = max; |
| 258 return value; |
| 259 } |
| 260 |
| 261 // Return true if a character belongs to the ASCII subset as defined in |
| 262 // GLSL ES 1.0 spec section 3.1. |
| 263 bool validateCharacter(unsigned char c) |
| 264 { |
| 265 // Printing characters are valid except " $ ` @ \ ' DEL. |
| 266 if (c >= 32 && c <= 126 |
| 267 && c != '"' && c != '$' && c != '`' && c != '@' && c != '\\' && c != '\'
') |
| 268 return true; |
| 269 // Horizontal tab, line feed, vertical tab, form feed, carriage return |
| 270 // are also valid. |
| 271 if (c >= 9 && c <= 13) |
| 272 return true; |
| 273 return false; |
| 274 } |
| 275 |
| 276 bool isPrefixReserved(const String& name) |
| 277 { |
| 278 if (name.startsWith("gl_") || name.startsWith("webgl_") || name.startsWith("
_webgl_")) |
| 279 return true; |
| 280 return false; |
| 281 } |
| 282 |
| 283 // Strips comments from shader text. This allows non-ASCII characters |
| 284 // to be used in comments without potentially breaking OpenGL |
| 285 // implementations not expecting characters outside the GLSL ES set. |
| 286 class StripComments { |
| 287 public: |
| 288 StripComments(const String& str) |
| 289 : m_parseState(BeginningOfLine) |
| 290 , m_sourceString(str) |
| 291 , m_length(str.length()) |
| 292 , m_position(0) |
| 293 { |
| 294 parse(); |
| 295 } |
| 296 |
| 297 String result() |
| 298 { |
| 299 return m_builder.toString(); |
| 300 } |
| 301 |
| 302 private: |
| 303 bool hasMoreCharacters() const |
| 304 { |
| 305 return (m_position < m_length); |
| 306 } |
| 307 |
| 308 void parse() |
| 309 { |
| 310 while (hasMoreCharacters()) { |
| 311 process(current()); |
| 312 // process() might advance the position. |
| 313 if (hasMoreCharacters()) |
| 314 advance(); |
| 315 } |
| 316 } |
| 317 |
| 318 void process(UChar); |
| 319 |
| 320 bool peek(UChar& character) const |
| 321 { |
| 322 if (m_position + 1 >= m_length) |
| 323 return false; |
| 324 character = m_sourceString[m_position + 1]; |
| 325 return true; |
| 326 } |
| 327 |
| 328 UChar current() |
| 329 { |
| 330 ASSERT_WITH_SECURITY_IMPLICATION(m_position < m_length); |
| 331 return m_sourceString[m_position]; |
| 332 } |
| 333 |
| 334 void advance() |
| 335 { |
| 336 ++m_position; |
| 337 } |
| 338 |
| 339 static bool isNewline(UChar character) |
| 340 { |
| 341 // Don't attempt to canonicalize newline related characters. |
| 342 return (character == '\n' || character == '\r'); |
| 343 } |
| 344 |
| 345 void emit(UChar character) |
| 346 { |
| 347 m_builder.append(character); |
| 348 } |
| 349 |
| 350 enum ParseState { |
| 351 // Have not seen an ASCII non-whitespace character yet on |
| 352 // this line. Possible that we might see a preprocessor |
| 353 // directive. |
| 354 BeginningOfLine, |
| 355 |
| 356 // Have seen at least one ASCII non-whitespace character |
| 357 // on this line. |
| 358 MiddleOfLine, |
| 359 |
| 360 // Handling a preprocessor directive. Passes through all |
| 361 // characters up to the end of the line. Disables comment |
| 362 // processing. |
| 363 InPreprocessorDirective, |
| 364 |
| 365 // Handling a single-line comment. The comment text is |
| 366 // replaced with a single space. |
| 367 InSingleLineComment, |
| 368 |
| 369 // Handling a multi-line comment. Newlines are passed |
| 370 // through to preserve line numbers. |
| 371 InMultiLineComment |
250 }; | 372 }; |
251 | 373 |
252 GLint clamp(GLint value, GLint min, GLint max) | 374 ParseState m_parseState; |
253 { | 375 String m_sourceString; |
254 if (value < min) | 376 unsigned m_length; |
255 value = min; | 377 unsigned m_position; |
256 if (value > max) | 378 StringBuilder m_builder; |
257 value = max; | 379 }; |
258 return value; | 380 |
259 } | 381 void StripComments::process(UChar c) |
260 | 382 { |
261 // Return true if a character belongs to the ASCII subset as defined in | 383 if (isNewline(c)) { |
262 // GLSL ES 1.0 spec section 3.1. | 384 // No matter what state we are in, pass through newlines |
263 bool validateCharacter(unsigned char c) | 385 // so we preserve line numbers. |
264 { | 386 emit(c); |
265 // Printing characters are valid except " $ ` @ \ ' DEL. | 387 |
266 if (c >= 32 && c <= 126 | 388 if (m_parseState != InMultiLineComment) |
267 && c != '"' && c != '$' && c != '`' && c != '@' && c != '\\' && c !=
'\'') | 389 m_parseState = BeginningOfLine; |
268 return true; | 390 |
269 // Horizontal tab, line feed, vertical tab, form feed, carriage return | 391 return; |
270 // are also valid. | 392 } |
271 if (c >= 9 && c <= 13) | 393 |
272 return true; | 394 UChar temp = 0; |
273 return false; | 395 switch (m_parseState) { |
274 } | 396 case BeginningOfLine: |
275 | 397 if (WTF::isASCIISpace(c)) { |
276 bool isPrefixReserved(const String& name) | |
277 { | |
278 if (name.startsWith("gl_") || name.startsWith("webgl_") || name.startsWi
th("_webgl_")) | |
279 return true; | |
280 return false; | |
281 } | |
282 | |
283 // Strips comments from shader text. This allows non-ASCII characters | |
284 // to be used in comments without potentially breaking OpenGL | |
285 // implementations not expecting characters outside the GLSL ES set. | |
286 class StripComments { | |
287 public: | |
288 StripComments(const String& str) | |
289 : m_parseState(BeginningOfLine) | |
290 , m_sourceString(str) | |
291 , m_length(str.length()) | |
292 , m_position(0) | |
293 { | |
294 parse(); | |
295 } | |
296 | |
297 String result() | |
298 { | |
299 return m_builder.toString(); | |
300 } | |
301 | |
302 private: | |
303 bool hasMoreCharacters() const | |
304 { | |
305 return (m_position < m_length); | |
306 } | |
307 | |
308 void parse() | |
309 { | |
310 while (hasMoreCharacters()) { | |
311 process(current()); | |
312 // process() might advance the position. | |
313 if (hasMoreCharacters()) | |
314 advance(); | |
315 } | |
316 } | |
317 | |
318 void process(UChar); | |
319 | |
320 bool peek(UChar& character) const | |
321 { | |
322 if (m_position + 1 >= m_length) | |
323 return false; | |
324 character = m_sourceString[m_position + 1]; | |
325 return true; | |
326 } | |
327 | |
328 UChar current() | |
329 { | |
330 ASSERT_WITH_SECURITY_IMPLICATION(m_position < m_length); | |
331 return m_sourceString[m_position]; | |
332 } | |
333 | |
334 void advance() | |
335 { | |
336 ++m_position; | |
337 } | |
338 | |
339 static bool isNewline(UChar character) | |
340 { | |
341 // Don't attempt to canonicalize newline related characters. | |
342 return (character == '\n' || character == '\r'); | |
343 } | |
344 | |
345 void emit(UChar character) | |
346 { | |
347 m_builder.append(character); | |
348 } | |
349 | |
350 enum ParseState { | |
351 // Have not seen an ASCII non-whitespace character yet on | |
352 // this line. Possible that we might see a preprocessor | |
353 // directive. | |
354 BeginningOfLine, | |
355 | |
356 // Have seen at least one ASCII non-whitespace character | |
357 // on this line. | |
358 MiddleOfLine, | |
359 | |
360 // Handling a preprocessor directive. Passes through all | |
361 // characters up to the end of the line. Disables comment | |
362 // processing. | |
363 InPreprocessorDirective, | |
364 | |
365 // Handling a single-line comment. The comment text is | |
366 // replaced with a single space. | |
367 InSingleLineComment, | |
368 | |
369 // Handling a multi-line comment. Newlines are passed | |
370 // through to preserve line numbers. | |
371 InMultiLineComment | |
372 }; | |
373 | |
374 ParseState m_parseState; | |
375 String m_sourceString; | |
376 unsigned m_length; | |
377 unsigned m_position; | |
378 StringBuilder m_builder; | |
379 }; | |
380 | |
381 void StripComments::process(UChar c) | |
382 { | |
383 if (isNewline(c)) { | |
384 // No matter what state we are in, pass through newlines | |
385 // so we preserve line numbers. | |
386 emit(c); | |
387 | |
388 if (m_parseState != InMultiLineComment) | |
389 m_parseState = BeginningOfLine; | |
390 | |
391 return; | |
392 } | |
393 | |
394 UChar temp = 0; | |
395 switch (m_parseState) { | |
396 case BeginningOfLine: | |
397 if (WTF::isASCIISpace(c)) { | |
398 emit(c); | |
399 break; | |
400 } | |
401 | |
402 if (c == '#') { | |
403 m_parseState = InPreprocessorDirective; | |
404 emit(c); | |
405 break; | |
406 } | |
407 | |
408 // Transition to normal state and re-handle character. | |
409 m_parseState = MiddleOfLine; | |
410 process(c); | |
411 break; | |
412 | |
413 case MiddleOfLine: | |
414 if (c == '/' && peek(temp)) { | |
415 if (temp == '/') { | |
416 m_parseState = InSingleLineComment; | |
417 emit(' '); | |
418 advance(); | |
419 break; | |
420 } | |
421 | |
422 if (temp == '*') { | |
423 m_parseState = InMultiLineComment; | |
424 // Emit the comment start in case the user has | |
425 // an unclosed comment and we want to later | |
426 // signal an error. | |
427 emit('/'); | |
428 emit('*'); | |
429 advance(); | |
430 break; | |
431 } | |
432 } | |
433 | |
434 emit(c); | 398 emit(c); |
435 break; | 399 break; |
436 | 400 } |
437 case InPreprocessorDirective: | 401 |
438 // No matter what the character is, just pass it | 402 if (c == '#') { |
439 // through. Do not parse comments in this state. This | 403 m_parseState = InPreprocessorDirective; |
440 // might not be the right thing to do long term, but it | |
441 // should handle the #error preprocessor directive. | |
442 emit(c); | 404 emit(c); |
443 break; | 405 break; |
444 | 406 } |
445 case InSingleLineComment: | 407 |
446 // The newline code at the top of this function takes care | 408 // Transition to normal state and re-handle character. |
447 // of resetting our state when we get out of the | 409 m_parseState = MiddleOfLine; |
448 // single-line comment. Swallow all other characters. | 410 process(c); |
449 break; | 411 break; |
450 | 412 |
451 case InMultiLineComment: | 413 case MiddleOfLine: |
452 if (c == '*' && peek(temp) && temp == '/') { | 414 if (c == '/' && peek(temp)) { |
453 emit('*'); | 415 if (temp == '/') { |
454 emit('/'); | 416 m_parseState = InSingleLineComment; |
455 m_parseState = MiddleOfLine; | 417 emit(' '); |
456 advance(); | 418 advance(); |
457 break; | 419 break; |
458 } | 420 } |
459 | 421 |
460 // Swallow all other characters. Unclear whether we may | 422 if (temp == '*') { |
461 // want or need to just emit a space per character to try | 423 m_parseState = InMultiLineComment; |
462 // to preserve column numbers for debugging purposes. | 424 // Emit the comment start in case the user has |
| 425 // an unclosed comment and we want to later |
| 426 // signal an error. |
| 427 emit('/'); |
| 428 emit('*'); |
| 429 advance(); |
| 430 break; |
| 431 } |
| 432 } |
| 433 |
| 434 emit(c); |
| 435 break; |
| 436 |
| 437 case InPreprocessorDirective: |
| 438 // No matter what the character is, just pass it |
| 439 // through. Do not parse comments in this state. This |
| 440 // might not be the right thing to do long term, but it |
| 441 // should handle the #error preprocessor directive. |
| 442 emit(c); |
| 443 break; |
| 444 |
| 445 case InSingleLineComment: |
| 446 // The newline code at the top of this function takes care |
| 447 // of resetting our state when we get out of the |
| 448 // single-line comment. Swallow all other characters. |
| 449 break; |
| 450 |
| 451 case InMultiLineComment: |
| 452 if (c == '*' && peek(temp) && temp == '/') { |
| 453 emit('*'); |
| 454 emit('/'); |
| 455 m_parseState = MiddleOfLine; |
| 456 advance(); |
463 break; | 457 break; |
464 } | 458 } |
465 } | 459 |
466 | 460 // Swallow all other characters. Unclear whether we may |
467 static bool shouldFailContextCreationForTesting = false; | 461 // want or need to just emit a space per character to try |
| 462 // to preserve column numbers for debugging purposes. |
| 463 break; |
| 464 } |
| 465 } |
| 466 |
| 467 static bool shouldFailContextCreationForTesting = false; |
468 } // namespace anonymous | 468 } // namespace anonymous |
469 | 469 |
470 class ScopedTexture2DRestorer { | 470 class ScopedTexture2DRestorer { |
471 STACK_ALLOCATED(); | 471 STACK_ALLOCATED(); |
472 public: | 472 public: |
473 explicit ScopedTexture2DRestorer(WebGLRenderingContextBase* context) | 473 explicit ScopedTexture2DRestorer(WebGLRenderingContextBase* context) |
474 : m_context(context) | 474 : m_context(context) |
475 { | 475 { |
476 } | 476 } |
477 | 477 |
(...skipping 5910 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6388 } | 6388 } |
6389 | 6389 |
6390 void WebGLRenderingContextBase::LRUImageBufferCache::bubbleToFront(int idx) | 6390 void WebGLRenderingContextBase::LRUImageBufferCache::bubbleToFront(int idx) |
6391 { | 6391 { |
6392 for (int i = idx; i > 0; --i) | 6392 for (int i = idx; i > 0; --i) |
6393 m_buffers[i].swap(m_buffers[i-1]); | 6393 m_buffers[i].swap(m_buffers[i-1]); |
6394 } | 6394 } |
6395 | 6395 |
6396 namespace { | 6396 namespace { |
6397 | 6397 |
6398 String GetErrorString(GLenum error) | 6398 String GetErrorString(GLenum error) |
6399 { | 6399 { |
6400 switch (error) { | 6400 switch (error) { |
6401 case GL_INVALID_ENUM: | 6401 case GL_INVALID_ENUM: |
6402 return "INVALID_ENUM"; | 6402 return "INVALID_ENUM"; |
6403 case GL_INVALID_VALUE: | 6403 case GL_INVALID_VALUE: |
6404 return "INVALID_VALUE"; | 6404 return "INVALID_VALUE"; |
6405 case GL_INVALID_OPERATION: | 6405 case GL_INVALID_OPERATION: |
6406 return "INVALID_OPERATION"; | 6406 return "INVALID_OPERATION"; |
6407 case GL_OUT_OF_MEMORY: | 6407 case GL_OUT_OF_MEMORY: |
6408 return "OUT_OF_MEMORY"; | 6408 return "OUT_OF_MEMORY"; |
6409 case GL_INVALID_FRAMEBUFFER_OPERATION: | 6409 case GL_INVALID_FRAMEBUFFER_OPERATION: |
6410 return "INVALID_FRAMEBUFFER_OPERATION"; | 6410 return "INVALID_FRAMEBUFFER_OPERATION"; |
6411 case GC3D_CONTEXT_LOST_WEBGL: | 6411 case GC3D_CONTEXT_LOST_WEBGL: |
6412 return "CONTEXT_LOST_WEBGL"; | 6412 return "CONTEXT_LOST_WEBGL"; |
6413 default: | 6413 default: |
6414 return String::format("WebGL ERROR(0x%04X)", error); | 6414 return String::format("WebGL ERROR(0x%04X)", error); |
6415 } | |
6416 } | 6415 } |
| 6416 } |
6417 | 6417 |
6418 } // namespace anonymous | 6418 } // namespace anonymous |
6419 | 6419 |
6420 void WebGLRenderingContextBase::synthesizeGLError(GLenum error, const char* func
tionName, const char* description, ConsoleDisplayPreference display) | 6420 void WebGLRenderingContextBase::synthesizeGLError(GLenum error, const char* func
tionName, const char* description, ConsoleDisplayPreference display) |
6421 { | 6421 { |
6422 String errorType = GetErrorString(error); | 6422 String errorType = GetErrorString(error); |
6423 if (m_synthesizedErrorsToConsole && display == DisplayInConsole) { | 6423 if (m_synthesizedErrorsToConsole && display == DisplayInConsole) { |
6424 String message = String("WebGL: ") + errorType + ": " + String(function
Name) + ": " + String(description); | 6424 String message = String("WebGL: ") + errorType + ": " + String(function
Name) + ": " + String(description); |
6425 printGLErrorToConsole(message); | 6425 printGLErrorToConsole(message); |
6426 } | 6426 } |
(...skipping 179 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6606 | 6606 |
6607 return totalBytesPerPixel; | 6607 return totalBytesPerPixel; |
6608 } | 6608 } |
6609 | 6609 |
6610 DrawingBuffer* WebGLRenderingContextBase::drawingBuffer() const | 6610 DrawingBuffer* WebGLRenderingContextBase::drawingBuffer() const |
6611 { | 6611 { |
6612 return m_drawingBuffer.get(); | 6612 return m_drawingBuffer.get(); |
6613 } | 6613 } |
6614 | 6614 |
6615 } // namespace blink | 6615 } // namespace blink |
OLD | NEW |