| 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 |