| // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef GPU_COMMAND_BUFFER_SERVICE_BUFFER_MANAGER_H_ |
| #define GPU_COMMAND_BUFFER_SERVICE_BUFFER_MANAGER_H_ |
| |
| #include <stdarg.h> |
| #include <stddef.h> |
| #include <stdint.h> |
| |
| #include <map> |
| #include <memory> |
| #include <vector> |
| |
| #include "base/containers/hash_tables.h" |
| #include "base/debug/stack_trace.h" |
| #include "base/logging.h" |
| #include "base/macros.h" |
| #include "base/memory/ref_counted.h" |
| #include "gpu/command_buffer/common/buffer.h" |
| #include "gpu/command_buffer/service/gl_utils.h" |
| #include "gpu/command_buffer/service/memory_tracking.h" |
| #include "gpu/gpu_gles2_export.h" |
| |
| namespace gpu { |
| namespace gles2 { |
| |
| class BufferManager; |
| struct ContextState; |
| class ErrorState; |
| class FeatureInfo; |
| class IndexedBufferBindingHost; |
| class TestHelper; |
| |
| // Info about Buffers currently in the system. |
| class GPU_GLES2_EXPORT Buffer : public base::RefCounted<Buffer> { |
| public: |
| struct MappedRange { |
| GLintptr offset; |
| GLsizeiptr size; |
| GLenum access; |
| void* pointer; // Pointer returned by driver. |
| scoped_refptr<gpu::Buffer> shm; // Client side mem buffer. |
| unsigned int shm_offset; // Client side mem buffer offset. |
| |
| MappedRange(GLintptr offset, GLsizeiptr size, GLenum access, void* pointer, |
| scoped_refptr<gpu::Buffer> shm, unsigned int shm_offset); |
| ~MappedRange(); |
| void* GetShmPointer() const; |
| }; |
| |
| Buffer(BufferManager* manager, GLuint service_id); |
| |
| GLenum initial_target() const { return initial_target_; } |
| |
| GLuint service_id() const { |
| return service_id_; |
| } |
| |
| GLsizeiptr size() const { |
| return size_; |
| } |
| |
| GLenum usage() const { |
| return usage_; |
| } |
| |
| bool shadowed() const { |
| return !shadow_.empty(); |
| } |
| |
| // Gets the maximum value in the buffer for the given range interpreted as |
| // the given type. Returns false if offset and count are out of range. |
| // offset is in bytes. |
| // count is in elements of type. |
| bool GetMaxValueForRange(GLuint offset, GLsizei count, GLenum type, |
| bool primitive_restart_enabled, GLuint* max_value); |
| |
| // Returns a pointer to shadowed data. |
| const void* GetRange(GLintptr offset, GLsizeiptr size) const; |
| |
| // Check if an offset, size range is valid for the current buffer. |
| bool CheckRange(GLintptr offset, GLsizeiptr size) const; |
| |
| // Sets a range of this buffer's shadowed data. |
| void SetRange(GLintptr offset, GLsizeiptr size, const GLvoid * data); |
| |
| bool IsDeleted() const { |
| return deleted_; |
| } |
| |
| bool IsValid() const { |
| return initial_target() && !IsDeleted(); |
| } |
| |
| bool IsClientSideArray() const { |
| return is_client_side_array_; |
| } |
| |
| void SetMappedRange(GLintptr offset, GLsizeiptr size, GLenum access, |
| void* pointer, scoped_refptr<gpu::Buffer> shm, |
| unsigned int shm_offset); |
| void RemoveMappedRange(); |
| const MappedRange* GetMappedRange() const { |
| return mapped_range_.get(); |
| } |
| |
| // These maintain the reference counts for checking whether a buffer is |
| // double-bound to transform feedback and non-transform-feedback binding |
| // points. |
| void OnBind(GLenum target, bool indexed); |
| void OnUnbind(GLenum target, bool indexed); |
| |
| bool IsBoundForTransformFeedbackAndOther() const { |
| return transform_feedback_indexed_binding_count_ > 0 && |
| non_transform_feedback_binding_count_ > 0; |
| } |
| |
| bool IsDoubleBoundForTransformFeedback() const { |
| return transform_feedback_indexed_binding_count_ > 1; |
| } |
| |
| void SetReadbackShadowAllocation(scoped_refptr<gpu::Buffer> shm, |
| uint32_t shm_offset); |
| scoped_refptr<gpu::Buffer> TakeReadbackShadowAllocation(void** data); |
| |
| private: |
| friend class BufferManager; |
| friend class BufferManagerTestBase; |
| friend class base::RefCounted<Buffer>; |
| |
| // Represents a range in a buffer. |
| class Range { |
| public: |
| Range(GLuint offset, GLsizei count, GLenum type, |
| bool primitive_restart_enabled) |
| : offset_(offset), |
| count_(count), |
| type_(type), |
| primitive_restart_enabled_(primitive_restart_enabled) { |
| } |
| |
| // A less functor provided for std::map so it can find ranges. |
| struct Less { |
| bool operator() (const Range& lhs, const Range& rhs) const { |
| if (lhs.offset_ != rhs.offset_) { |
| return lhs.offset_ < rhs.offset_; |
| } |
| if (lhs.count_ != rhs.count_) { |
| return lhs.count_ < rhs.count_; |
| } |
| if (lhs.type_ != rhs.type_) { |
| return lhs.type_ < rhs.type_; |
| } |
| return lhs.primitive_restart_enabled_ < rhs.primitive_restart_enabled_; |
| } |
| }; |
| |
| private: |
| GLuint offset_; |
| GLsizei count_; |
| GLenum type_; |
| bool primitive_restart_enabled_; |
| }; |
| |
| ~Buffer(); |
| |
| void set_initial_target(GLenum target) { |
| DCHECK_EQ(0u, initial_target_); |
| initial_target_ = target; |
| } |
| |
| void MarkAsDeleted() { |
| deleted_ = true; |
| } |
| |
| // Setup the shadow buffer. This will either initialize the shadow buffer |
| // with the passed data or clear the shadow buffer if no shadow required. This |
| // will return a pointer to the shadowed data if using shadow, otherwise will |
| // return the original data pointer. |
| const GLvoid* StageShadow(bool use_shadow, |
| GLsizeiptr size, |
| const GLvoid* data); |
| |
| // Sets the size, usage and initial data of a buffer. |
| // If shadow is true then if data is NULL buffer will be initialized to 0. |
| void SetInfo(GLsizeiptr size, |
| GLenum usage, |
| bool use_shadow, |
| bool is_client_side_array); |
| |
| // Clears any cache of index ranges. |
| void ClearCache(); |
| |
| // The manager that owns this Buffer. |
| BufferManager* manager_; |
| |
| // A copy of the data in the buffer. This data is only kept if the conditions |
| // checked in UseShadowBuffer() are true. |
| std::vector<uint8_t> shadow_; |
| |
| // Size of buffer. |
| GLsizeiptr size_; |
| |
| // True if deleted. |
| bool deleted_; |
| |
| // Whether or not this Buffer is not uploaded to the GPU but just |
| // sitting in local memory. |
| bool is_client_side_array_; |
| |
| // Keeps track of whether this buffer is currently bound for transform |
| // feedback in a WebGL context. Used as an optimization when validating WebGL |
| // draw calls for compliance with binding restrictions. |
| // http://crbug.com/696345 |
| int non_transform_feedback_binding_count_ = 0; |
| int transform_feedback_indexed_binding_count_ = 0; |
| |
| // Service side buffer id. |
| GLuint service_id_; |
| |
| // The first target of buffer. 0 = unset. |
| // It is set the first time bindBuffer() is called and cannot be changed. |
| GLenum initial_target_; |
| |
| // Usage of buffer. |
| GLenum usage_; |
| |
| // Data cached from last glMapBufferRange call. |
| std::unique_ptr<MappedRange> mapped_range_; |
| |
| // A map of ranges to the highest value in that range of a certain type. |
| typedef std::map<Range, GLuint, Range::Less> RangeToMaxValueMap; |
| RangeToMaxValueMap range_set_; |
| |
| scoped_refptr<gpu::Buffer> readback_shm_; |
| uint32_t readback_shm_offset_ = 0; |
| }; |
| |
| // This class keeps track of the buffers and their sizes so we can do |
| // bounds checking. |
| // |
| // NOTE: To support shared resources an instance of this class will need to be |
| // shared by multiple GLES2Decoders. |
| class GPU_GLES2_EXPORT BufferManager |
| : public base::trace_event::MemoryDumpProvider { |
| public: |
| BufferManager(MemoryTracker* memory_tracker, FeatureInfo* feature_info); |
| ~BufferManager() override; |
| |
| void MarkContextLost(); |
| |
| // Must call before destruction. |
| void Destroy(); |
| |
| // Creates a Buffer for the given buffer. |
| void CreateBuffer(GLuint client_id, GLuint service_id); |
| |
| // Gets the buffer info for the given buffer. |
| Buffer* GetBuffer(GLuint client_id); |
| |
| // Removes a buffer info for the given buffer. |
| void RemoveBuffer(GLuint client_id); |
| |
| // Gets a client id for a given service id. |
| bool GetClientId(GLuint service_id, GLuint* client_id) const; |
| |
| // Validates a glBufferSubData, and then calls DoBufferData if validation was |
| // successful. |
| void ValidateAndDoBufferSubData(ContextState* context_state, |
| ErrorState* error_state, |
| GLenum target, |
| GLintptr offset, |
| GLsizeiptr size, |
| const GLvoid* data); |
| |
| // Validates a glBufferData, and then calls DoBufferData if validation was |
| // successful. |
| void ValidateAndDoBufferData(ContextState* context_state, |
| ErrorState* error_state, |
| GLenum target, |
| GLsizeiptr size, |
| const GLvoid* data, |
| GLenum usage); |
| |
| // Validates a glCopyBufferSubData, and then calls DoCopyBufferSubData if |
| // validation was successful. |
| void ValidateAndDoCopyBufferSubData(ContextState* context_state, |
| ErrorState* error_state, |
| GLenum readtarget, |
| GLenum writetarget, |
| GLintptr readoffset, |
| GLintptr writeoffset, |
| GLsizeiptr size); |
| |
| // Validates a glGetBufferParameteri64v, and then calls GetBufferParameteri64v |
| // if validation was successful. |
| void ValidateAndDoGetBufferParameteri64v(ContextState* context_state, |
| ErrorState* error_state, |
| GLenum target, |
| GLenum pname, |
| GLint64* params); |
| |
| // Validates a glGetBufferParameteriv, and then calls GetBufferParameteriv if |
| // validation was successful. |
| void ValidateAndDoGetBufferParameteriv(ContextState* context_state, |
| ErrorState* error_state, |
| GLenum target, |
| GLenum pname, |
| GLint* params); |
| |
| // Sets the target of a buffer. Returns false if the target can not be set. |
| bool SetTarget(Buffer* buffer, GLenum target); |
| |
| void set_max_buffer_size(GLsizeiptr max_buffer_size) { |
| max_buffer_size_ = max_buffer_size; |
| } |
| |
| void set_allow_buffers_on_multiple_targets(bool allow) { |
| allow_buffers_on_multiple_targets_ = allow; |
| } |
| |
| void set_allow_fixed_attribs(bool allow) { |
| allow_fixed_attribs_ = allow; |
| } |
| |
| size_t mem_represented() const { |
| return memory_type_tracker_->GetMemRepresented(); |
| } |
| |
| // Tells for a given usage if this would be a client side array. |
| bool IsUsageClientSideArray(GLenum usage); |
| |
| // Tells whether a buffer that is emulated using client-side arrays should be |
| // set to a non-zero size. |
| bool UseNonZeroSizeForClientSideArrayBuffer(); |
| |
| void SetPrimitiveRestartFixedIndexIfNecessary(GLenum type); |
| |
| Buffer* GetBufferInfoForTarget(ContextState* state, GLenum target) const; |
| |
| // base::trace_event::MemoryDumpProvider implementation. |
| bool OnMemoryDump(const base::trace_event::MemoryDumpArgs& args, |
| base::trace_event::ProcessMemoryDump* pmd) override; |
| |
| // Validate if a buffer is bound at target, if it's unmapped, if it's |
| // large enough. Return the buffer bound to |target| if access is granted; |
| // return nullptr if a GL error is generated. |
| // Generates INVALID_VALUE if offset + size is out of range. |
| Buffer* RequestBufferAccess(ContextState* context_state, |
| ErrorState* error_state, |
| GLenum target, |
| GLintptr offset, |
| GLsizeiptr size, |
| const char* func_name); |
| // Same as above, but assume to access the entire buffer. |
| Buffer* RequestBufferAccess(ContextState* context_state, |
| ErrorState* error_state, |
| GLenum target, |
| const char* func_name); |
| // Same as above, but it can be any buffer rather than the buffer bound to |
| // |target|. Return true if access is granted; return false if a GL error is |
| // generated. |
| bool RequestBufferAccess(ErrorState* error_state, |
| Buffer* buffer, |
| const char* func_name, |
| const char* error_message_format, |
| ...); |
| // Generates INVALID_OPERATION if offset + size is out of range. |
| bool RequestBufferAccess(ErrorState* error_state, |
| Buffer* buffer, |
| GLintptr offset, |
| GLsizeiptr size, |
| const char* func_name, |
| const char* error_message); |
| // Returns false and generates INVALID_OPERATION if buffer at binding |ii| |
| // doesn't exist, is mapped, or smaller than |variable_sizes[ii]| * |count|. |
| // Return true otherwise. |
| bool RequestBuffersAccess(ErrorState* error_state, |
| const IndexedBufferBindingHost* bindings, |
| const std::vector<GLsizeiptr>& variable_sizes, |
| GLsizei count, |
| const char* func_name, |
| const char* message_tag); |
| |
| private: |
| friend class Buffer; |
| friend class TestHelper; // Needs access to DoBufferData. |
| friend class BufferManagerTestBase; // Needs access to DoBufferSubData. |
| friend class IndexedBufferBindingHostTest; // Needs access to SetInfo. |
| |
| void StartTracking(Buffer* buffer); |
| void StopTracking(Buffer* buffer); |
| |
| // Does a glBufferSubData and updates the appropriate accounting. |
| // Assumes the values have already been validated. |
| void DoBufferSubData( |
| Buffer* buffer, |
| GLenum target, |
| GLintptr offset, |
| GLsizeiptr size, |
| const GLvoid* data); |
| |
| // Does a glBufferData and updates the appropriate accounting. |
| // Assumes the values have already been validated. |
| void DoBufferData( |
| ErrorState* error_state, |
| Buffer* buffer, |
| GLenum target, |
| GLsizeiptr size, |
| GLenum usage, |
| const GLvoid* data); |
| |
| // Does a glCopyBufferSubData and updates the appropriate accounting. |
| // Assumes the values have already been validated. |
| void DoCopyBufferSubData( |
| Buffer* readbuffer, |
| GLenum readtarget, |
| GLintptr readoffset, |
| Buffer* writebuffer, |
| GLenum writetarget, |
| GLintptr writeoffset, |
| GLsizeiptr size); |
| |
| // Tests whether a shadow buffer needs to be used. |
| bool UseShadowBuffer(GLenum target, GLenum usage); |
| |
| // Sets the size, usage and initial data of a buffer. |
| // If data is NULL buffer will be initialized to 0 if shadowed. |
| void SetInfo(Buffer* buffer, |
| GLenum target, |
| GLsizeiptr size, |
| GLenum usage, |
| bool use_shadow); |
| |
| // Same as public RequestBufferAccess taking similar arguments, but |
| // allows caller to assemble the va_list. |
| bool RequestBufferAccessV(ErrorState* error_state, |
| Buffer* buffer, |
| const char* func_name, |
| const char* error_message_format, |
| va_list varargs); |
| |
| std::unique_ptr<MemoryTypeTracker> memory_type_tracker_; |
| MemoryTracker* memory_tracker_; |
| scoped_refptr<FeatureInfo> feature_info_; |
| |
| // Info for each buffer in the system. |
| typedef base::hash_map<GLuint, scoped_refptr<Buffer> > BufferMap; |
| BufferMap buffers_; |
| |
| // The maximum size of buffers. |
| GLsizeiptr max_buffer_size_; |
| |
| // Whether or not buffers can be bound to multiple targets. |
| bool allow_buffers_on_multiple_targets_; |
| |
| // Whether or not allow using GL_FIXED type for vertex attribs. |
| bool allow_fixed_attribs_; |
| |
| // Counts the number of Buffer allocated with 'this' as its manager. |
| // Allows to check no Buffer will outlive this. |
| unsigned int buffer_count_; |
| |
| GLuint primitive_restart_fixed_index_; |
| |
| bool lost_context_; |
| bool use_client_side_arrays_for_stream_buffers_; |
| |
| DISALLOW_COPY_AND_ASSIGN(BufferManager); |
| }; |
| |
| } // namespace gles2 |
| } // namespace gpu |
| |
| #endif // GPU_COMMAND_BUFFER_SERVICE_BUFFER_MANAGER_H_ |