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 fc4f547a4d4e2cc3193d1498ea5fa16e85f273b2..e34e47675e123bedb23ce98bf90132059dd87d6d 100644 |
--- a/gpu/command_buffer/client/gles2_implementation.cc |
+++ b/gpu/command_buffer/client/gles2_implementation.cc |
@@ -6,6 +6,8 @@ |
#include "../client/gles2_implementation.h" |
+#include <set> |
+#include <queue> |
#include <GLES2/gl2ext.h> |
#include "../client/mapped_memory.h" |
#include "../client/program_info_manager.h" |
@@ -51,10 +53,11 @@ class NonSharedIdHandler : public IdHandlerInterface { |
} |
// Overridden from IdHandlerInterface. |
- virtual void FreeIds(GLsizei n, const GLuint* ids) { |
+ virtual bool FreeIds(GLsizei n, const GLuint* ids) { |
for (GLsizei ii = 0; ii < n; ++ii) { |
id_allocator_.FreeID(ids[ii]); |
} |
+ return true; |
} |
// Overridden from IdHandlerInterface. |
@@ -79,8 +82,9 @@ class NonSharedNonReusedIdHandler : public IdHandlerInterface { |
} |
// Overridden from IdHandlerInterface. |
- virtual void FreeIds(GLsizei /* n */, const GLuint* /* ids */) { |
+ virtual bool FreeIds(GLsizei /* n */, const GLuint* /* ids */) { |
// Ids are never freed. |
+ return true; |
} |
// Overridden from IdHandlerInterface. |
@@ -109,20 +113,109 @@ class SharedIdHandler : public IdHandlerInterface { |
gles2_->GenSharedIdsCHROMIUM(id_namespace_, id_offset, n, ids); |
} |
- virtual void FreeIds(GLsizei n, const GLuint* ids) { |
+ virtual bool FreeIds(GLsizei n, const GLuint* ids) { |
gles2_->DeleteSharedIdsCHROMIUM(id_namespace_, n, ids); |
+ return true; |
+ } |
+ |
+ virtual bool MarkAsUsedForBind(GLuint /* id */) { |
+ // This has no meaning for shared resources. |
+ return true; |
+ } |
+ |
+ private: |
+ GLES2Implementation* gles2_; |
+ id_namespaces::IdNamespaces id_namespace_; |
+}; |
+ |
+// An id handler for shared ids that requires ids are made before using and |
+// that only the context that created the id can delete it. |
+// Assumes the service will enforce that non made ids generate an error. |
+class StrictSharedIdHandler : public IdHandlerInterface { |
+ public: |
+ StrictSharedIdHandler( |
+ GLES2Implementation* gles2, |
+ id_namespaces::IdNamespaces id_namespace) |
+ : gles2_(gles2), |
+ id_namespace_(id_namespace) { |
+ } |
+ |
+ virtual ~StrictSharedIdHandler() { } |
+ |
+ virtual void MakeIds(GLuint id_offset, GLsizei n, GLuint* ids) { |
+ for (GLsizei ii = 0; ii < n; ++ii) { |
+ ids[ii] = GetId(id_offset); |
+ } |
} |
- virtual bool MarkAsUsedForBind(GLuint) { // NOLINT |
+ virtual bool FreeIds(GLsizei n, const GLuint* ids) { |
+ // OpenGL sematics. If any id is bad none of them get freed. |
+ for (GLsizei ii = 0; ii < n; ++ii) { |
+ GLuint id = ids[ii]; |
+ if (id != 0) { |
+ ResourceIdSet::iterator it = used_ids_.find(id); |
+ if (it == used_ids_.end()) { |
+ return false; |
+ } |
+ } |
+ } |
+ for (GLsizei ii = 0; ii < n; ++ii) { |
+ GLuint id = ids[ii]; |
+ if (id != 0) { |
+ ResourceIdSet::iterator it = used_ids_.find(id); |
+ if (it != used_ids_.end()) { |
+ used_ids_.erase(it); |
+ free_ids_.push(id); |
+ } |
+ } |
+ } |
+ return true; |
+ } |
+ |
+ virtual bool MarkAsUsedForBind(GLuint /* id */) { |
// This has no meaning for shared resources. |
return true; |
} |
private: |
+ static const GLsizei kNumIdsToGet = 2048; |
+ typedef std::queue<GLuint> ResourceIdQueue; |
+ typedef std::set<GLuint> ResourceIdSet; |
+ |
+ GLuint GetId(GLuint id_offset) { |
+ if (free_ids_.empty()) { |
+ GLuint ids[kNumIdsToGet]; |
+ gles2_->GenSharedIdsCHROMIUM(id_namespace_, id_offset, kNumIdsToGet, ids); |
+ for (GLsizei ii = 0; ii < kNumIdsToGet; ++ii) { |
+ free_ids_.push(ids[ii]); |
+ } |
+ } |
+ GLuint id = free_ids_.front(); |
+ free_ids_.pop(); |
+ used_ids_.insert(id); |
+ return id; |
+ } |
+ |
+ bool FreeId(GLuint id) { |
+ ResourceIdSet::iterator it = used_ids_.find(id); |
+ if (it == used_ids_.end()) { |
+ return false; |
+ } |
+ used_ids_.erase(it); |
+ free_ids_.push(id); |
+ return true; |
+ } |
+ |
GLES2Implementation* gles2_; |
id_namespaces::IdNamespaces id_namespace_; |
+ ResourceIdSet used_ids_; |
+ ResourceIdQueue free_ids_; |
}; |
+#ifndef _MSC_VER |
+const GLsizei StrictSharedIdHandler::kNumIdsToGet; |
+#endif |
+ |
static GLsizei RoundUpToMultipleOf4(GLsizei size) { |
return (size + 3) & ~3; |
} |
@@ -435,7 +528,8 @@ GLES2Implementation::GLES2Implementation( |
size_t transfer_buffer_size, |
void* transfer_buffer, |
int32 transfer_buffer_id, |
- bool share_resources) |
+ bool share_resources, |
+ bool bind_generates_resource) |
: helper_(helper), |
transfer_buffer_( |
kStartingOffset, |
@@ -455,7 +549,8 @@ GLES2Implementation::GLES2Implementation( |
client_side_element_array_id_(0), |
error_bits_(0), |
debug_(false), |
- sharing_resources_(share_resources) { |
+ sharing_resources_(share_resources), |
+ bind_generates_resource_(bind_generates_resource) { |
GPU_CLIENT_LOG_CODE_BLOCK({ |
debug_ = CommandLine::ForCurrentProcess()->HasSwitch( |
switches::kEnableGPUClientLogging); |
@@ -469,16 +564,29 @@ GLES2Implementation::GLES2Implementation( |
mapped_memory_.reset(new MappedMemoryManager(helper_)); |
if (share_resources) { |
- buffer_id_handler_.reset( |
- new SharedIdHandler(this, id_namespaces::kBuffers)); |
- framebuffer_id_handler_.reset( |
- new SharedIdHandler(this, id_namespaces::kFramebuffers)); |
- renderbuffer_id_handler_.reset( |
- new SharedIdHandler(this, id_namespaces::kRenderbuffers)); |
- program_and_shader_id_handler_.reset( |
- new SharedIdHandler(this, id_namespaces::kProgramsAndShaders)); |
- texture_id_handler_.reset( |
- new SharedIdHandler(this, id_namespaces::kTextures)); |
+ if (!bind_generates_resource) { |
+ buffer_id_handler_.reset( |
+ new StrictSharedIdHandler(this, id_namespaces::kBuffers)); |
+ framebuffer_id_handler_.reset( |
+ new StrictSharedIdHandler(this, id_namespaces::kFramebuffers)); |
+ renderbuffer_id_handler_.reset( |
+ new StrictSharedIdHandler(this, id_namespaces::kRenderbuffers)); |
+ program_and_shader_id_handler_.reset( |
+ new StrictSharedIdHandler(this, id_namespaces::kProgramsAndShaders)); |
+ texture_id_handler_.reset( |
+ new StrictSharedIdHandler(this, id_namespaces::kTextures)); |
+ } else { |
+ buffer_id_handler_.reset( |
+ new SharedIdHandler(this, id_namespaces::kBuffers)); |
+ framebuffer_id_handler_.reset( |
+ new SharedIdHandler(this, id_namespaces::kFramebuffers)); |
+ renderbuffer_id_handler_.reset( |
+ new SharedIdHandler(this, id_namespaces::kRenderbuffers)); |
+ program_and_shader_id_handler_.reset( |
+ new SharedIdHandler(this, id_namespaces::kProgramsAndShaders)); |
+ texture_id_handler_.reset( |
+ new SharedIdHandler(this, id_namespaces::kTextures)); |
+ } |
} else { |
buffer_id_handler_.reset(new NonSharedIdHandler()); |
framebuffer_id_handler_.reset(new NonSharedIdHandler()); |
@@ -514,7 +622,6 @@ GLES2Implementation::GLES2Implementation( |
texture_units_.reset( |
new TextureUnit[gl_state_.max_combined_texture_image_units]); |
- |
program_info_manager_.reset(ProgramInfoManager::Create(sharing_resources_)); |
#if defined(GLES2_SUPPORT_CLIENT_SIDE_ARRAYS) |
@@ -705,26 +812,44 @@ bool GLES2Implementation::GetHelper(GLenum pname, GLint* params) { |
*params = gl_state_.num_shader_binary_formats; |
return true; |
case GL_ARRAY_BUFFER_BINDING: |
- *params = bound_array_buffer_id_; |
- return true; |
+ if (bind_generates_resource_) { |
+ *params = bound_array_buffer_id_; |
+ return true; |
+ } |
+ return false; |
case GL_ELEMENT_ARRAY_BUFFER_BINDING: |
- *params = bound_element_array_buffer_id_; |
- return true; |
+ if (bind_generates_resource_) { |
+ *params = bound_element_array_buffer_id_; |
+ return true; |
+ } |
+ return false; |
case GL_ACTIVE_TEXTURE: |
*params = active_texture_unit_ + GL_TEXTURE0; |
return true; |
case GL_TEXTURE_BINDING_2D: |
- *params = texture_units_[active_texture_unit_].bound_texture_2d; |
- return true; |
+ if (bind_generates_resource_) { |
+ *params = texture_units_[active_texture_unit_].bound_texture_2d; |
+ return true; |
+ } |
+ return false; |
case GL_TEXTURE_BINDING_CUBE_MAP: |
- *params = texture_units_[active_texture_unit_].bound_texture_cube_map; |
- return true; |
+ if (bind_generates_resource_) { |
+ *params = texture_units_[active_texture_unit_].bound_texture_cube_map; |
+ return true; |
+ } |
+ return false; |
case GL_FRAMEBUFFER_BINDING: |
- *params = bound_framebuffer_; |
- return true; |
+ if (bind_generates_resource_) { |
+ *params = bound_framebuffer_; |
+ return true; |
+ } |
+ return false; |
case GL_RENDERBUFFER_BINDING: |
- *params = bound_renderbuffer_; |
- return true; |
+ if (bind_generates_resource_) { |
+ *params = bound_renderbuffer_; |
+ return true; |
+ } |
+ return false; |
default: |
return false; |
} |
@@ -857,13 +982,21 @@ void GLES2Implementation::GenSharedIdsCHROMIUM( |
} |
}); |
TRACE_EVENT0("gpu", "GLES2::GenSharedIdsCHROMIUM"); |
- GLint* id_buffer = transfer_buffer_.AllocTyped<GLint>(n); |
- helper_->GenSharedIdsCHROMIUM(namespace_id, id_offset, n, |
- transfer_buffer_id_, |
- transfer_buffer_.GetOffset(id_buffer)); |
- WaitForCmd(); |
- memcpy(ids, id_buffer, sizeof(*ids) * n); |
- transfer_buffer_.FreePendingToken(id_buffer, helper_->InsertToken()); |
+ GLsizei max_size = transfer_buffer_.GetLargestFreeOrPendingSize(); |
+ GLsizei max_num_per = max_size / sizeof(ids[0]); |
+ while (n) { |
+ GLsizei num = std::min(n, max_num_per); |
+ GLint* id_buffer = transfer_buffer_.AllocTyped<GLint>(num); |
+ helper_->GenSharedIdsCHROMIUM( |
+ namespace_id, id_offset, num, |
+ transfer_buffer_id_, |
+ transfer_buffer_.GetOffset(id_buffer)); |
+ WaitForCmd(); |
+ memcpy(ids, id_buffer, sizeof(*ids) * num); |
+ transfer_buffer_.FreePendingToken(id_buffer, helper_->InsertToken()); |
+ n -= num; |
+ ids += num; |
+ } |
} |
void GLES2Implementation::DeleteSharedIdsCHROMIUM( |
@@ -877,13 +1010,21 @@ void GLES2Implementation::DeleteSharedIdsCHROMIUM( |
} |
}); |
TRACE_EVENT0("gpu", "GLES2::DeleteSharedIdsCHROMIUM"); |
- GLint* id_buffer = transfer_buffer_.AllocTyped<GLint>(n); |
- memcpy(id_buffer, ids, sizeof(*ids) * n); |
- helper_->DeleteSharedIdsCHROMIUM(namespace_id, n, |
- transfer_buffer_id_, |
- transfer_buffer_.GetOffset(id_buffer)); |
- WaitForCmd(); |
- transfer_buffer_.FreePendingToken(id_buffer, helper_->InsertToken()); |
+ GLsizei max_size = transfer_buffer_.GetLargestFreeOrPendingSize(); |
+ GLsizei max_num_per = max_size / sizeof(ids[0]); |
+ while (n) { |
+ GLsizei num = std::min(n, max_num_per); |
+ GLint* id_buffer = transfer_buffer_.AllocTyped<GLint>(num); |
+ memcpy(id_buffer, ids, sizeof(*ids) * num); |
+ helper_->DeleteSharedIdsCHROMIUM( |
+ namespace_id, num, |
+ transfer_buffer_id_, |
+ transfer_buffer_.GetOffset(id_buffer)); |
+ WaitForCmd(); |
+ transfer_buffer_.FreePendingToken(id_buffer, helper_->InsertToken()); |
+ n -= num; |
+ ids += num; |
+ } |
} |
void GLES2Implementation::RegisterSharedIdsCHROMIUM( |
@@ -897,13 +1038,21 @@ void GLES2Implementation::RegisterSharedIdsCHROMIUM( |
} |
}); |
TRACE_EVENT0("gpu", "GLES2::RegisterSharedIdsCHROMIUM"); |
- GLint* id_buffer = transfer_buffer_.AllocTyped<GLint>(n); |
- memcpy(id_buffer, ids, sizeof(*ids) * n); |
- helper_->RegisterSharedIdsCHROMIUM(namespace_id, n, |
- transfer_buffer_id_, |
- transfer_buffer_.GetOffset(id_buffer)); |
- WaitForCmd(); |
- transfer_buffer_.FreePendingToken(id_buffer, helper_->InsertToken()); |
+ GLsizei max_size = transfer_buffer_.GetLargestFreeOrPendingSize(); |
+ GLsizei max_num_per = max_size / sizeof(ids[0]); |
+ while (n) { |
+ GLsizei num = std::min(n, max_num_per); |
+ GLint* id_buffer = transfer_buffer_.AllocTyped<GLint>(n); |
+ memcpy(id_buffer, ids, sizeof(*ids) * n); |
+ helper_->RegisterSharedIdsCHROMIUM( |
+ namespace_id, n, |
+ transfer_buffer_id_, |
+ transfer_buffer_.GetOffset(id_buffer)); |
+ WaitForCmd(); |
+ transfer_buffer_.FreePendingToken(id_buffer, helper_->InsertToken()); |
+ n -= num; |
+ ids += num; |
+ } |
} |
void GLES2Implementation::BindAttribLocation( |
@@ -943,10 +1092,30 @@ void GLES2Implementation::GetVertexAttribPointerv( |
}); |
} |
-void GLES2Implementation::DeleteProgramOrShaderHelper( |
- GLuint program_or_shader) { |
- program_and_shader_id_handler_->FreeIds(1, &program_or_shader); |
- program_info_manager_->DeleteInfo(program_or_shader); |
+bool GLES2Implementation::DeleteProgramHelper(GLuint program) { |
+ if (!program_and_shader_id_handler_->FreeIds(1, &program)) { |
+ SetGLError( |
+ GL_INVALID_VALUE, |
+ "glDeleteProgram: id not created by this context."); |
+ return false; |
+ } |
+ program_info_manager_->DeleteInfo(program); |
+ helper_->DeleteProgram(program); |
+ Flush(); |
+ return true; |
+} |
+ |
+bool GLES2Implementation::DeleteShaderHelper(GLuint shader) { |
+ if (!program_and_shader_id_handler_->FreeIds(1, &shader)) { |
+ SetGLError( |
+ GL_INVALID_VALUE, |
+ "glDeleteShader: id not created by this context."); |
+ return false; |
+ } |
+ program_info_manager_->DeleteInfo(shader); |
+ helper_->DeleteShader(shader); |
+ Flush(); |
+ return true; |
} |
GLint GLES2Implementation::GetAttribLocationHelper( |
@@ -1964,7 +2133,12 @@ bool GLES2Implementation::IsBufferReservedId(GLuint /* id */) { |
void GLES2Implementation::DeleteBuffersHelper( |
GLsizei n, const GLuint* buffers) { |
- buffer_id_handler_->FreeIds(n, buffers); |
+ if (!buffer_id_handler_->FreeIds(n, buffers)) { |
+ SetGLError( |
+ GL_INVALID_VALUE, |
+ "glDeleteBuffers: id not created by this context."); |
+ return; |
+ } |
for (GLsizei ii = 0; ii < n; ++ii) { |
if (buffers[ii] == bound_array_buffer_id_) { |
bound_array_buffer_id_ = 0; |
@@ -1973,31 +2147,52 @@ void GLES2Implementation::DeleteBuffersHelper( |
bound_element_array_buffer_id_ = 0; |
} |
} |
+ helper_->DeleteBuffersImmediate(n, buffers); |
+ Flush(); |
} |
void GLES2Implementation::DeleteFramebuffersHelper( |
GLsizei n, const GLuint* framebuffers) { |
- framebuffer_id_handler_->FreeIds(n, framebuffers); |
+ if (!framebuffer_id_handler_->FreeIds(n, framebuffers)) { |
+ SetGLError( |
+ GL_INVALID_VALUE, |
+ "glDeleteFramebuffers: id not created by this context."); |
+ return; |
+ } |
for (GLsizei ii = 0; ii < n; ++ii) { |
if (framebuffers[ii] == bound_framebuffer_) { |
bound_framebuffer_ = 0; |
} |
} |
+ helper_->DeleteFramebuffersImmediate(n, framebuffers); |
+ Flush(); |
} |
void GLES2Implementation::DeleteRenderbuffersHelper( |
GLsizei n, const GLuint* renderbuffers) { |
- renderbuffer_id_handler_->FreeIds(n, renderbuffers); |
+ if (!renderbuffer_id_handler_->FreeIds(n, renderbuffers)) { |
+ SetGLError( |
+ GL_INVALID_VALUE, |
+ "glDeleteRenderbuffers: id not created by this context."); |
+ return; |
+ } |
for (GLsizei ii = 0; ii < n; ++ii) { |
if (renderbuffers[ii] == bound_renderbuffer_) { |
bound_renderbuffer_ = 0; |
} |
} |
+ helper_->DeleteRenderbuffersImmediate(n, renderbuffers); |
+ Flush(); |
} |
void GLES2Implementation::DeleteTexturesHelper( |
GLsizei n, const GLuint* textures) { |
- texture_id_handler_->FreeIds(n, textures); |
+ if (!texture_id_handler_->FreeIds(n, textures)) { |
+ SetGLError( |
+ GL_INVALID_VALUE, |
+ "glDeleteTextures: id not created by this context."); |
+ return; |
+ } |
for (GLsizei ii = 0; ii < n; ++ii) { |
for (GLint tt = 0; tt < gl_state_.max_combined_texture_image_units; ++tt) { |
TextureUnit& unit = texture_units_[active_texture_unit_]; |
@@ -2009,6 +2204,8 @@ void GLES2Implementation::DeleteTexturesHelper( |
} |
} |
} |
+ helper_->DeleteTexturesImmediate(n, textures); |
+ Flush(); |
} |
void GLES2Implementation::DisableVertexAttribArray(GLuint index) { |
@@ -2428,3 +2625,4 @@ void GLES2Implementation::GetProgramInfoCHROMIUM( |
} // namespace gles2 |
} // namespace gpu |
+ |