| Index: gpu/command_buffer/client/gles2_implementation.cc
|
| diff --git a/gpu/command_buffer/client/gles2_implementation.cc b/gpu/command_buffer/client/gles2_implementation.cc
|
| index fc051b1fad3bfa6b1a9d2c61c2999cde84f192ee..aeaa565559b6478b4962feeec7be954edbd0b763 100644
|
| --- a/gpu/command_buffer/client/gles2_implementation.cc
|
| +++ b/gpu/command_buffer/client/gles2_implementation.cc
|
| @@ -18,6 +18,7 @@
|
| #include <sstream>
|
| #include <string>
|
| #include "base/compiler_specific.h"
|
| +#include "base/strings/string_split.h"
|
| #include "base/strings/stringprintf.h"
|
| #include "base/sys_info.h"
|
| #include "base/thread_task_runner_handle.h"
|
| @@ -131,6 +132,7 @@ GLES2Implementation::GLES2Implementation(
|
| gpu_control_(gpu_control),
|
| capabilities_(gpu_control->GetCapabilities()),
|
| aggressively_free_resources_(false),
|
| + cached_extension_string_(nullptr),
|
| weak_ptr_factory_(this) {
|
| DCHECK(helper);
|
| DCHECK(transfer_buffer);
|
| @@ -950,7 +952,8 @@ bool GLES2Implementation::GetHelper(GLenum pname, GLint* params) {
|
| *params = capabilities_.minor_version;
|
| return true;
|
| case GL_NUM_EXTENSIONS:
|
| - *params = capabilities_.num_extensions;
|
| + UpdateCachedExtensionsIfNeeded();
|
| + *params = cached_extensions_.size();
|
| return true;
|
| case GL_NUM_PROGRAM_BINARY_FORMATS:
|
| *params = capabilities_.num_program_binary_formats;
|
| @@ -3292,6 +3295,9 @@ void GLES2Implementation::GetShaderPrecisionFormat(
|
| }
|
|
|
| const GLubyte* GLES2Implementation::GetStringHelper(GLenum name) {
|
| + if (name == GL_EXTENSIONS && cached_extension_string_) {
|
| + return reinterpret_cast<const GLubyte*>(cached_extension_string_);
|
| + }
|
| const char* result = NULL;
|
| // Clears the bucket so if the command fails nothing will be in it.
|
| helper_->SetBucketSize(kResultBucketId, 0);
|
| @@ -3299,40 +3305,33 @@ const GLubyte* GLES2Implementation::GetStringHelper(GLenum name) {
|
| std::string str;
|
| if (GetBucketAsString(kResultBucketId, &str)) {
|
| // Adds extensions implemented on client side only.
|
| - switch (name) {
|
| - case GL_EXTENSIONS:
|
| - str += std::string(str.empty() ? "" : " ") +
|
| - "GL_EXT_unpack_subimage "
|
| - "GL_CHROMIUM_map_sub";
|
| - if (capabilities_.image)
|
| - str += " GL_CHROMIUM_image GL_CHROMIUM_gpu_memory_buffer_image";
|
| - if (capabilities_.future_sync_points)
|
| - str += " GL_CHROMIUM_future_sync_point";
|
| - break;
|
| - default:
|
| - break;
|
| + if (name == GL_EXTENSIONS) {
|
| + str += std::string(str.empty() ? "" : " ") +
|
| + "GL_EXT_unpack_subimage "
|
| + "GL_CHROMIUM_map_sub";
|
| + if (capabilities_.image)
|
| + str += " GL_CHROMIUM_image GL_CHROMIUM_gpu_memory_buffer_image";
|
| + if (capabilities_.future_sync_points)
|
| + str += " GL_CHROMIUM_future_sync_point";
|
| }
|
|
|
| // Because of WebGL the extensions can change. We have to cache each unique
|
| // result since we don't know when the client will stop referring to a
|
| // previous one it queries.
|
| - GLStringMap::iterator it = gl_strings_.find(name);
|
| - if (it == gl_strings_.end()) {
|
| - std::set<std::string> strings;
|
| - std::pair<GLStringMap::iterator, bool> insert_result =
|
| - gl_strings_.insert(std::make_pair(name, strings));
|
| - DCHECK(insert_result.second);
|
| - it = insert_result.first;
|
| - }
|
| - std::set<std::string>& string_set = it->second;
|
| - std::set<std::string>::const_iterator sit = string_set.find(str);
|
| - if (sit != string_set.end()) {
|
| - result = sit->c_str();
|
| - } else {
|
| - std::pair<std::set<std::string>::const_iterator, bool> insert_result =
|
| - string_set.insert(str);
|
| - DCHECK(insert_result.second);
|
| - result = insert_result.first->c_str();
|
| + // TODO: Here we could save memory by defining RequestExtensions
|
| + // invalidating the GL_EXTENSIONS string. http://crbug.com/586414
|
| + const std::string& cache = *gl_strings_.insert(str).first;
|
| + result = cache.c_str();
|
| +
|
| + if (name == GL_EXTENSIONS) {
|
| + cached_extension_string_ = result;
|
| + std::vector<std::string> extensions =
|
| + base::SplitString(cache, base::kWhitespaceASCII,
|
| + base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
|
| + for (const std::string& extension : extensions) {
|
| + cached_extensions_.push_back(
|
| + gl_strings_.insert(extension).first->c_str());
|
| + }
|
| }
|
| }
|
| return reinterpret_cast<const GLubyte*>(result);
|
| @@ -3349,6 +3348,28 @@ const GLubyte* GLES2Implementation::GetString(GLenum name) {
|
| return result;
|
| }
|
|
|
| +const GLubyte* GLES2Implementation::GetStringi(GLenum name, GLuint index) {
|
| + GPU_CLIENT_SINGLE_THREAD_CHECK();
|
| + GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetStringi("
|
| + << GLES2Util::GetStringStringType(name) << "," << index
|
| + << ")");
|
| + TRACE_EVENT0("gpu", "GLES2::GetStringi");
|
| + UpdateCachedExtensionsIfNeeded();
|
| + if (name != GL_EXTENSIONS) {
|
| + SetGLError(GL_INVALID_ENUM, "glGetStringi", "name");
|
| + return nullptr;
|
| + }
|
| + if (index >= cached_extensions_.size()) {
|
| + SetGLError(GL_INVALID_VALUE, "glGetStringi", "index too large");
|
| + return nullptr;
|
| + }
|
| +
|
| + const char* result = cached_extensions_[index];
|
| + GPU_CLIENT_LOG(" returned " << result);
|
| + CheckGLError();
|
| + return reinterpret_cast<const GLubyte*>(result);
|
| +}
|
| +
|
| bool GLES2Implementation::GetTransformFeedbackVaryingHelper(
|
| GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size,
|
| GLenum* type, char* name) {
|
| @@ -4815,16 +4836,9 @@ const GLchar* GLES2Implementation::GetRequestableExtensionsCHROMIUM() {
|
| // them. Because we don't know when the client will stop referring
|
| // to a previous one it queries (see GetString) we need to cache
|
| // the unique results.
|
| - std::set<std::string>::const_iterator sit =
|
| - requestable_extensions_set_.find(str);
|
| - if (sit != requestable_extensions_set_.end()) {
|
| - result = sit->c_str();
|
| - } else {
|
| - std::pair<std::set<std::string>::const_iterator, bool> insert_result =
|
| - requestable_extensions_set_.insert(str);
|
| - DCHECK(insert_result.second);
|
| - result = insert_result.first->c_str();
|
| - }
|
| + // TODO: Here we could save memory by defining RequestExtensions
|
| + // invalidating the GL_EXTENSIONS string. http://crbug.com/586414
|
| + result = gl_strings_.insert(str).first->c_str();
|
| }
|
| GPU_CLIENT_LOG(" returned " << result);
|
| return reinterpret_cast<const GLchar*>(result);
|
| @@ -4836,6 +4850,7 @@ void GLES2Implementation::RequestExtensionCHROMIUM(const char* extension) {
|
| GPU_CLIENT_SINGLE_THREAD_CHECK();
|
| GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glRequestExtensionCHROMIUM("
|
| << extension << ")");
|
| + InvalidateCachedExtensions();
|
| SetBucketAsCString(kResultBucketId, extension);
|
| helper_->RequestExtensionCHROMIUM(kResultBucketId);
|
| helper_->SetBucketSize(kResultBucketId, 0);
|
| @@ -6547,6 +6562,18 @@ void GLES2Implementation::ProgramPathFragmentInputGenCHROMIUM(
|
| CheckGLError();
|
| }
|
|
|
| +void GLES2Implementation::UpdateCachedExtensionsIfNeeded() {
|
| + if (cached_extension_string_) {
|
| + return;
|
| + }
|
| + GetStringHelper(GL_EXTENSIONS);
|
| +}
|
| +
|
| +void GLES2Implementation::InvalidateCachedExtensions() {
|
| + cached_extension_string_ = nullptr;
|
| + cached_extensions_.clear();
|
| +}
|
| +
|
| // Include the auto-generated part of this file. We split this because it means
|
| // we can easily edit the non-auto generated parts right here in this file
|
| // instead of having to edit some template or the code generator.
|
|
|