Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 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 "gpu/command_buffer/service/texture_manager.h" | 5 #include "gpu/command_buffer/service/texture_manager.h" |
| 6 | 6 |
| 7 #include <stddef.h> | 7 #include <stddef.h> |
| 8 #include <stdint.h> | 8 #include <stdint.h> |
| 9 | 9 |
| 10 #include <algorithm> | 10 #include <algorithm> |
| (...skipping 245 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 256 (lhs.format == rhs.format) && | 256 (lhs.format == rhs.format) && |
| 257 (lhs.type < rhs.type))); | 257 (lhs.type < rhs.type))); |
| 258 } | 258 } |
| 259 }; | 259 }; |
| 260 | 260 |
| 261 // This class needs to be thread safe, so once supported_combinations_ | 261 // This class needs to be thread safe, so once supported_combinations_ |
| 262 // are initialized in the constructor, it should never be modified later. | 262 // are initialized in the constructor, it should never be modified later. |
| 263 std::set<FormatType, FormatTypeCompare> supported_combinations_; | 263 std::set<FormatType, FormatTypeCompare> supported_combinations_; |
| 264 }; | 264 }; |
| 265 | 265 |
| 266 // A 32-bit and 64-bit compatible way of converting a pointer to a GLuint. | |
| 267 GLuint ToGLuint(const void* ptr) { | |
| 268 return static_cast<GLuint>(reinterpret_cast<size_t>(ptr)); | |
| 269 } | |
| 270 | |
| 266 base::LazyInstance<const FormatTypeValidator>::Leaky g_format_type_validator = | 271 base::LazyInstance<const FormatTypeValidator>::Leaky g_format_type_validator = |
| 267 LAZY_INSTANCE_INITIALIZER; | 272 LAZY_INSTANCE_INITIALIZER; |
| 268 | 273 |
| 269 } // namespace anonymous | 274 } // namespace anonymous |
| 270 | 275 |
| 271 TextureManager::DestructionObserver::DestructionObserver() {} | 276 TextureManager::DestructionObserver::DestructionObserver() {} |
| 272 | 277 |
| 273 TextureManager::DestructionObserver::~DestructionObserver() {} | 278 TextureManager::DestructionObserver::~DestructionObserver() {} |
| 274 | 279 |
| 275 TextureManager::~TextureManager() { | 280 TextureManager::~TextureManager() { |
| (...skipping 1831 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2107 "unknown texture for target"); | 2112 "unknown texture for target"); |
| 2108 return false; | 2113 return false; |
| 2109 } | 2114 } |
| 2110 if (local_texture_ref->texture()->IsImmutable()) { | 2115 if (local_texture_ref->texture()->IsImmutable()) { |
| 2111 ERRORSTATE_SET_GL_ERROR( | 2116 ERRORSTATE_SET_GL_ERROR( |
| 2112 error_state, GL_INVALID_OPERATION, function_name, | 2117 error_state, GL_INVALID_OPERATION, function_name, |
| 2113 "texture is immutable"); | 2118 "texture is immutable"); |
| 2114 return false; | 2119 return false; |
| 2115 } | 2120 } |
| 2116 | 2121 |
| 2122 Buffer* buffer = state->bound_pixel_unpack_buffer.get(); | |
| 2123 if (buffer) { | |
| 2124 if (buffer->GetMappedRange()) { | |
| 2125 ERRORSTATE_SET_GL_ERROR( | |
| 2126 error_state, GL_INVALID_OPERATION, function_name, | |
| 2127 "pixel unpack buffer should not be mapped to client memory"); | |
| 2128 return error::kNoError; | |
| 2129 } | |
| 2130 base::CheckedNumeric<uint32_t> size = args.pixels_size; | |
| 2131 size += ToGLuint(args.pixels); | |
| 2132 if (!size.IsValid()) { | |
| 2133 ERRORSTATE_SET_GL_ERROR( | |
| 2134 error_state, GL_INVALID_VALUE, function_name, | |
| 2135 "size + offset overflow"); | |
| 2136 return error::kNoError; | |
| 2137 } | |
| 2138 uint32_t buffer_size = static_cast<uint32_t>(buffer->size()); | |
| 2139 if (buffer_size < size.ValueOrDefault(0)) { | |
| 2140 ERRORSTATE_SET_GL_ERROR( | |
| 2141 error_state, GL_INVALID_OPERATION, function_name, | |
| 2142 "pixel unpack buffer is not large enough"); | |
| 2143 return error::kNoError; | |
| 2144 } | |
| 2145 size_t type_size = GLES2Util::GetGLTypeSizeForTextures(args.type); | |
| 2146 DCHECK_LT(0u, type_size); | |
| 2147 if (buffer_size % type_size != 0) { | |
|
piman
2016/03/08 01:56:50
Why this check? The buffer size doesn't matter, as
Zhenyao Mo
2016/03/09 18:41:05
See ES Spec 3.0.4 page 113, under $3.7 -> Unpackin
piman
2016/03/09 18:52:05
I still don't get it. The 2 requirements are:
1- t
| |
| 2148 ERRORSTATE_SET_GL_ERROR( | |
| 2149 error_state, GL_INVALID_OPERATION, function_name, | |
| 2150 "buffer size is not evenly divisible by elements"); | |
| 2151 return error::kNoError; | |
| 2152 } | |
| 2153 } | |
| 2154 | |
| 2117 if (!memory_type_tracker_->EnsureGPUMemoryAvailable(args.pixels_size)) { | 2155 if (!memory_type_tracker_->EnsureGPUMemoryAvailable(args.pixels_size)) { |
| 2118 ERRORSTATE_SET_GL_ERROR(error_state, GL_OUT_OF_MEMORY, function_name, | 2156 ERRORSTATE_SET_GL_ERROR(error_state, GL_OUT_OF_MEMORY, function_name, |
| 2119 "out of memory"); | 2157 "out of memory"); |
| 2120 return false; | 2158 return false; |
| 2121 } | 2159 } |
| 2122 | 2160 |
| 2123 // Write the TextureReference since this is valid. | 2161 // Write the TextureReference since this is valid. |
| 2124 *texture_ref = local_texture_ref; | 2162 *texture_ref = local_texture_ref; |
| 2125 return true; | 2163 return true; |
| 2126 } | 2164 } |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2171 ERRORSTATE_SET_GL_ERROR(state->GetErrorState(), GL_OUT_OF_MEMORY, | 2209 ERRORSTATE_SET_GL_ERROR(state->GetErrorState(), GL_OUT_OF_MEMORY, |
| 2172 function_name, "out of memory"); | 2210 function_name, "out of memory"); |
| 2173 return; | 2211 return; |
| 2174 } | 2212 } |
| 2175 DoTexImageArguments new_args = args; | 2213 DoTexImageArguments new_args = args; |
| 2176 scoped_ptr<char[]> zero(new char[args.pixels_size]); | 2214 scoped_ptr<char[]> zero(new char[args.pixels_size]); |
| 2177 memset(zero.get(), 0, args.pixels_size); | 2215 memset(zero.get(), 0, args.pixels_size); |
| 2178 for (GLenum face : undefined_faces) { | 2216 for (GLenum face : undefined_faces) { |
| 2179 new_args.target = face; | 2217 new_args.target = face; |
| 2180 new_args.pixels = zero.get(); | 2218 new_args.pixels = zero.get(); |
| 2181 DoTexImage(texture_state, state->GetErrorState(), framebuffer_state, | 2219 DoTexImage(texture_state, state, framebuffer_state, |
| 2182 function_name, texture_ref, new_args); | 2220 function_name, texture_ref, new_args); |
| 2183 texture->MarkLevelAsInternalWorkaround(face, args.level); | 2221 texture->MarkLevelAsInternalWorkaround(face, args.level); |
| 2184 } | 2222 } |
| 2185 } | 2223 } |
| 2186 | 2224 |
| 2187 DoTexImage(texture_state, state->GetErrorState(), framebuffer_state, | 2225 DoTexImage(texture_state, state, framebuffer_state, |
| 2188 function_name, texture_ref, args); | 2226 function_name, texture_ref, args); |
| 2189 } | 2227 } |
| 2190 | 2228 |
| 2191 bool TextureManager::ValidateTexSubImage(ContextState* state, | 2229 bool TextureManager::ValidateTexSubImage(ContextState* state, |
| 2192 const char* function_name, | 2230 const char* function_name, |
| 2193 const DoTexSubImageArguments& args, | 2231 const DoTexSubImageArguments& args, |
| 2194 TextureRef** texture_ref) { | 2232 TextureRef** texture_ref) { |
| 2195 ErrorState* error_state = state->GetErrorState(); | 2233 ErrorState* error_state = state->GetErrorState(); |
| 2196 const Validators* validators = feature_info_->validators(); | 2234 const Validators* validators = feature_info_->validators(); |
| 2197 | 2235 |
| 2198 if ((args.command_type == DoTexSubImageArguments::kTexSubImage2D && | 2236 if ((args.command_type == DoTexSubImageArguments::kTexSubImage2D && |
| 2199 !validators->texture_target.IsValid(args.target)) || | 2237 !validators->texture_target.IsValid(args.target)) || |
| 2200 (args.command_type == DoTexSubImageArguments::kTexSubImage3D && | 2238 (args.command_type == DoTexSubImageArguments::kTexSubImage3D && |
| 2201 !validators->texture_3_d_target.IsValid(args.target))) { | 2239 !validators->texture_3_d_target.IsValid(args.target))) { |
| 2202 ERRORSTATE_SET_GL_ERROR_INVALID_ENUM(error_state, function_name, | 2240 ERRORSTATE_SET_GL_ERROR_INVALID_ENUM(error_state, function_name, |
| 2203 args.target, "target"); | 2241 args.target, "target"); |
| 2204 return false; | 2242 return false; |
| 2205 } | 2243 } |
| 2206 if (args.width < 0) { | 2244 DCHECK(args.width >= 0 && args.height >= 0 && args.depth >= 0); |
| 2207 ERRORSTATE_SET_GL_ERROR(error_state, GL_INVALID_VALUE, function_name, | |
| 2208 "width < 0"); | |
| 2209 return false; | |
| 2210 } | |
| 2211 if (args.height < 0) { | |
| 2212 ERRORSTATE_SET_GL_ERROR(error_state, GL_INVALID_VALUE, function_name, | |
| 2213 "height < 0"); | |
| 2214 return false; | |
| 2215 } | |
| 2216 if (args.depth < 0) { | |
| 2217 ERRORSTATE_SET_GL_ERROR(error_state, GL_INVALID_VALUE, function_name, | |
| 2218 "depth < 0"); | |
| 2219 return false; | |
| 2220 } | |
| 2221 TextureRef* local_texture_ref = GetTextureInfoForTarget(state, args.target); | 2245 TextureRef* local_texture_ref = GetTextureInfoForTarget(state, args.target); |
| 2222 if (!local_texture_ref) { | 2246 if (!local_texture_ref) { |
| 2223 ERRORSTATE_SET_GL_ERROR(error_state, GL_INVALID_OPERATION, function_name, | 2247 ERRORSTATE_SET_GL_ERROR(error_state, GL_INVALID_OPERATION, function_name, |
| 2224 "unknown texture for target"); | 2248 "unknown texture for target"); |
| 2225 return false; | 2249 return false; |
| 2226 } | 2250 } |
| 2227 Texture* texture = local_texture_ref->texture(); | 2251 Texture* texture = local_texture_ref->texture(); |
| 2228 GLenum current_type = 0; | 2252 GLenum current_type = 0; |
| 2229 GLenum internal_format = 0; | 2253 GLenum internal_format = 0; |
| 2230 if (!texture->GetLevelType(args.target, args.level, ¤t_type, | 2254 if (!texture->GetLevelType(args.target, args.level, ¤t_type, |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 2252 return false; | 2276 return false; |
| 2253 } | 2277 } |
| 2254 if ((GLES2Util::GetChannelsForFormat(args.format) & | 2278 if ((GLES2Util::GetChannelsForFormat(args.format) & |
| 2255 (GLES2Util::kDepth | GLES2Util::kStencil)) != 0 && | 2279 (GLES2Util::kDepth | GLES2Util::kStencil)) != 0 && |
| 2256 !feature_info_->IsES3Enabled()) { | 2280 !feature_info_->IsES3Enabled()) { |
| 2257 ERRORSTATE_SET_GL_ERROR( | 2281 ERRORSTATE_SET_GL_ERROR( |
| 2258 error_state, GL_INVALID_OPERATION, function_name, | 2282 error_state, GL_INVALID_OPERATION, function_name, |
| 2259 "can not supply data for depth or stencil textures"); | 2283 "can not supply data for depth or stencil textures"); |
| 2260 return false; | 2284 return false; |
| 2261 } | 2285 } |
| 2262 DCHECK(args.pixels); | 2286 |
| 2287 Buffer* buffer = state->bound_pixel_unpack_buffer.get(); | |
| 2288 if (buffer) { | |
| 2289 if (buffer->GetMappedRange()) { | |
| 2290 ERRORSTATE_SET_GL_ERROR( | |
| 2291 error_state, GL_INVALID_OPERATION, function_name, | |
| 2292 "pixel unpack buffer should not be mapped to client memory"); | |
| 2293 return error::kNoError; | |
| 2294 } | |
| 2295 base::CheckedNumeric<uint32_t> size = args.pixels_size; | |
| 2296 size += ToGLuint(args.pixels); | |
| 2297 if (!size.IsValid()) { | |
| 2298 ERRORSTATE_SET_GL_ERROR( | |
| 2299 error_state, GL_INVALID_VALUE, function_name, | |
| 2300 "size + offset overflow"); | |
| 2301 return error::kNoError; | |
| 2302 } | |
| 2303 uint32_t buffer_size = static_cast<uint32_t>(buffer->size()); | |
| 2304 if (buffer_size < size.ValueOrDefault(0)) { | |
| 2305 ERRORSTATE_SET_GL_ERROR( | |
| 2306 error_state, GL_INVALID_OPERATION, function_name, | |
| 2307 "pixel unpack buffer is not large enough"); | |
| 2308 return error::kNoError; | |
| 2309 } | |
| 2310 size_t type_size = GLES2Util::GetGLTypeSizeForTextures(args.type); | |
| 2311 DCHECK_LT(0u, type_size); | |
| 2312 if (buffer_size % type_size != 0) { | |
|
piman
2016/03/08 01:56:50
Same here
Zhenyao Mo
2016/03/09 18:41:05
Same answer. It is specified in a difference plac
| |
| 2313 ERRORSTATE_SET_GL_ERROR( | |
| 2314 error_state, GL_INVALID_OPERATION, function_name, | |
| 2315 "buffer size is not evenly divisible by elements"); | |
| 2316 return error::kNoError; | |
| 2317 } | |
| 2318 } | |
| 2263 *texture_ref = local_texture_ref; | 2319 *texture_ref = local_texture_ref; |
| 2264 return true; | 2320 return true; |
| 2265 } | 2321 } |
| 2266 | 2322 |
| 2267 void TextureManager::ValidateAndDoTexSubImage( | 2323 void TextureManager::ValidateAndDoTexSubImage( |
| 2268 GLES2Decoder* decoder, | 2324 GLES2Decoder* decoder, |
| 2269 DecoderTextureState* texture_state, | 2325 DecoderTextureState* texture_state, |
| 2270 ContextState* state, | 2326 ContextState* state, |
| 2271 DecoderFramebufferState* framebuffer_state, | 2327 DecoderFramebufferState* framebuffer_state, |
| 2272 const char* function_name, | 2328 const char* function_name, |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2358 if (format == GL_SRGB_EXT) | 2414 if (format == GL_SRGB_EXT) |
| 2359 return GL_RGB; | 2415 return GL_RGB; |
| 2360 if (format == GL_SRGB_ALPHA_EXT) | 2416 if (format == GL_SRGB_ALPHA_EXT) |
| 2361 return GL_RGBA; | 2417 return GL_RGBA; |
| 2362 } | 2418 } |
| 2363 return format; | 2419 return format; |
| 2364 } | 2420 } |
| 2365 | 2421 |
| 2366 void TextureManager::DoTexImage( | 2422 void TextureManager::DoTexImage( |
| 2367 DecoderTextureState* texture_state, | 2423 DecoderTextureState* texture_state, |
| 2368 ErrorState* error_state, | 2424 ContextState* state, |
| 2369 DecoderFramebufferState* framebuffer_state, | 2425 DecoderFramebufferState* framebuffer_state, |
| 2370 const char* function_name, | 2426 const char* function_name, |
| 2371 TextureRef* texture_ref, | 2427 TextureRef* texture_ref, |
| 2372 const DoTexImageArguments& args) { | 2428 const DoTexImageArguments& args) { |
| 2429 ErrorState* error_state = state->GetErrorState(); | |
| 2373 Texture* texture = texture_ref->texture(); | 2430 Texture* texture = texture_ref->texture(); |
| 2374 GLsizei tex_width = 0; | 2431 GLsizei tex_width = 0; |
| 2375 GLsizei tex_height = 0; | 2432 GLsizei tex_height = 0; |
| 2376 GLsizei tex_depth = 0; | 2433 GLsizei tex_depth = 0; |
| 2377 GLenum tex_type = 0; | 2434 GLenum tex_type = 0; |
| 2378 GLenum tex_internal_format = 0; | 2435 GLenum tex_internal_format = 0; |
| 2379 bool level_is_same = | 2436 bool level_is_same = |
| 2380 texture->GetLevelSize( | 2437 texture->GetLevelSize( |
| 2381 args.target, args.level, &tex_width, &tex_height, &tex_depth) && | 2438 args.target, args.level, &tex_width, &tex_height, &tex_depth) && |
| 2382 args.width == tex_width && args.height == tex_height && | 2439 args.width == tex_width && args.height == tex_height && |
| 2383 args.depth == tex_depth && | 2440 args.depth == tex_depth && |
| 2384 texture->GetLevelType( | 2441 texture->GetLevelType( |
| 2385 args.target, args.level, &tex_type, &tex_internal_format) && | 2442 args.target, args.level, &tex_type, &tex_internal_format) && |
| 2386 args.type == tex_type && args.internal_format == tex_internal_format; | 2443 args.type == tex_type && args.internal_format == tex_internal_format; |
| 2387 | 2444 |
| 2388 if (level_is_same && !args.pixels) { | 2445 bool unpack_buffer_bound = |
| 2446 (state->bound_pixel_unpack_buffer.get() != nullptr); | |
| 2447 | |
| 2448 if (level_is_same && !args.pixels && !unpack_buffer_bound) { | |
| 2389 // Just set the level texture but mark the texture as uncleared. | 2449 // Just set the level texture but mark the texture as uncleared. |
| 2390 SetLevelInfo( | 2450 SetLevelInfo( |
| 2391 texture_ref, args.target, args.level, args.internal_format, args.width, | 2451 texture_ref, args.target, args.level, args.internal_format, args.width, |
| 2392 args.height, args.depth, args.border, args.format, args.type, | 2452 args.height, args.depth, args.border, args.format, args.type, |
| 2393 gfx::Rect()); | 2453 gfx::Rect()); |
| 2394 texture_state->tex_image_failed = false; | 2454 texture_state->tex_image_failed = false; |
| 2395 return; | 2455 return; |
| 2396 } | 2456 } |
| 2397 | 2457 |
| 2398 if (texture->IsAttachedToFramebuffer()) { | 2458 if (texture->IsAttachedToFramebuffer()) { |
| 2399 framebuffer_state->clear_state_dirty = true; | 2459 framebuffer_state->clear_state_dirty = true; |
| 2400 } | 2460 } |
| 2401 | 2461 |
| 2402 if (texture_state->texsubimage_faster_than_teximage && | 2462 if (texture_state->texsubimage_faster_than_teximage && |
| 2403 level_is_same && args.pixels) { | 2463 level_is_same && args.pixels && !unpack_buffer_bound) { |
| 2404 { | 2464 { |
| 2405 ScopedTextureUploadTimer timer(texture_state); | 2465 ScopedTextureUploadTimer timer(texture_state); |
| 2406 if (args.command_type == DoTexImageArguments::kTexImage3D) { | 2466 if (args.command_type == DoTexImageArguments::kTexImage3D) { |
| 2407 glTexSubImage3D(args.target, args.level, 0, 0, 0, | 2467 glTexSubImage3D(args.target, args.level, 0, 0, 0, |
| 2408 args.width, args.height, args.depth, | 2468 args.width, args.height, args.depth, |
| 2409 args.format, args.type, args.pixels); | 2469 args.format, args.type, args.pixels); |
| 2410 } else { | 2470 } else { |
| 2411 glTexSubImage2D(args.target, args.level, 0, 0, args.width, args.height, | 2471 glTexSubImage2D(args.target, args.level, 0, 0, args.width, args.height, |
| 2412 AdjustTexFormat(args.format), args.type, args.pixels); | 2472 AdjustTexFormat(args.format), args.type, args.pixels); |
| 2413 } | 2473 } |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 2434 } | 2494 } |
| 2435 GLenum error = ERRORSTATE_PEEK_GL_ERROR(error_state, function_name); | 2495 GLenum error = ERRORSTATE_PEEK_GL_ERROR(error_state, function_name); |
| 2436 if (args.command_type == DoTexImageArguments::kTexImage3D) { | 2496 if (args.command_type == DoTexImageArguments::kTexImage3D) { |
| 2437 UMA_HISTOGRAM_CUSTOM_ENUMERATION("GPU.Error.TexImage3D", error, | 2497 UMA_HISTOGRAM_CUSTOM_ENUMERATION("GPU.Error.TexImage3D", error, |
| 2438 GetAllGLErrors()); | 2498 GetAllGLErrors()); |
| 2439 } else { | 2499 } else { |
| 2440 UMA_HISTOGRAM_CUSTOM_ENUMERATION("GPU.Error.TexImage2D", error, | 2500 UMA_HISTOGRAM_CUSTOM_ENUMERATION("GPU.Error.TexImage2D", error, |
| 2441 GetAllGLErrors()); | 2501 GetAllGLErrors()); |
| 2442 } | 2502 } |
| 2443 if (error == GL_NO_ERROR) { | 2503 if (error == GL_NO_ERROR) { |
| 2444 bool set_as_cleared = (args.pixels != nullptr); | 2504 bool set_as_cleared = (args.pixels != nullptr || unpack_buffer_bound); |
| 2445 SetLevelInfo( | 2505 SetLevelInfo( |
| 2446 texture_ref, args.target, args.level, args.internal_format, args.width, | 2506 texture_ref, args.target, args.level, args.internal_format, args.width, |
| 2447 args.height, args.depth, args.border, args.format, args.type, | 2507 args.height, args.depth, args.border, args.format, args.type, |
| 2448 set_as_cleared ? gfx::Rect(args.width, args.height) : gfx::Rect()); | 2508 set_as_cleared ? gfx::Rect(args.width, args.height) : gfx::Rect()); |
| 2449 texture_state->tex_image_failed = false; | 2509 texture_state->tex_image_failed = false; |
| 2450 } | 2510 } |
| 2451 } | 2511 } |
| 2452 | 2512 |
| 2453 bool TextureManager::CombineAdjacentRects(const gfx::Rect& rect1, | 2513 bool TextureManager::CombineAdjacentRects(const gfx::Rect& rect1, |
| 2454 const gfx::Rect& rect2, | 2514 const gfx::Rect& rect2, |
| (...skipping 353 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2808 uint32_t TextureManager::GetServiceIdGeneration() const { | 2868 uint32_t TextureManager::GetServiceIdGeneration() const { |
| 2809 return current_service_id_generation_; | 2869 return current_service_id_generation_; |
| 2810 } | 2870 } |
| 2811 | 2871 |
| 2812 void TextureManager::IncrementServiceIdGeneration() { | 2872 void TextureManager::IncrementServiceIdGeneration() { |
| 2813 current_service_id_generation_++; | 2873 current_service_id_generation_++; |
| 2814 } | 2874 } |
| 2815 | 2875 |
| 2816 } // namespace gles2 | 2876 } // namespace gles2 |
| 2817 } // namespace gpu | 2877 } // namespace gpu |
| OLD | NEW |