1 // Copyright (c) 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef GPU_COMMAND_BUFFER_SERVICE_INDEXED_BUFFER_BINDING_HOST_H_
6 #define GPU_COMMAND_BUFFER_SERVICE_INDEXED_BUFFER_BINDING_HOST_H_
7 
8 #include <vector>
9 
10 #include "base/memory/ref_counted.h"
11 #include "gpu/command_buffer/service/gl_utils.h"
12 #include "gpu/gpu_gles2_export.h"
13 
14 namespace gpu {
15 namespace gles2 {
16 
17 class Buffer;
18 
19 // This is a base class for indexed buffer bindings tracking.
20 // TransformFeedback and Program should inherit from this base class,
21 // for tracking indexed TRANSFORM_FEEDBACK_BUFFER / UNIFORM_BUFFER bindings.
22 class GPU_GLES2_EXPORT IndexedBufferBindingHost
23     : public base::RefCounted<IndexedBufferBindingHost> {
24  public:
25   // In theory |needs_emulation| needs to be true on Desktop GL 4.1 or lower.
26   // However, we set it to true everywhere, not to trust drivers to handle
27   // out-of-bounds buffer accesses.
28   IndexedBufferBindingHost(uint32_t max_bindings,
29                            GLenum target,
30                            bool needs_emulation,
31                            bool round_down_uniform_bind_buffer_range_size);
32 
33   // The following two functions do state update and call the underlying GL
34   // function.  All validations have been done already and the GL function is
35   // guaranteed to succeed.
36   void DoBindBufferBase(GLuint index, Buffer* buffer);
37   void DoBindBufferRange(GLuint index,
38                          Buffer* buffer,
39                          GLintptr offset,
40                          GLsizeiptr size);
41 
42   // This is called on the active host when glBufferData is called and buffer
43   // size might change.
44   void OnBufferData(Buffer* buffer);
45 
46   void RemoveBoundBuffer(GLenum target,
47                          Buffer* buffer,
48                          Buffer* target_generic_bound_buffer,
49                          bool have_context);
50 
51   void SetIsBound(bool bound);
52 
53   Buffer* GetBufferBinding(GLuint index) const;
54   // Returns |size| set by glBindBufferRange; 0 if set by glBindBufferBase.
55   GLsizeiptr GetBufferSize(GLuint index) const;
56   // For glBindBufferBase, return the actual buffer size when this function is
57   // called, not when glBindBufferBase is called.
58   // For glBindBufferRange, return the |size| set by glBindBufferRange minus
59   // the range that's beyond the buffer.
60   GLsizeiptr GetEffectiveBufferSize(GLuint index) const;
61   GLintptr GetBufferStart(GLuint index) const;
62 
63   // This is used only for UNIFORM_BUFFER bindings in context switching.
64   void RestoreBindings(IndexedBufferBindingHost* prev);
65 
66   // Check if |buffer| is currently bound to one of the indexed binding point
67   // from 0 to |used_binding_count| - 1.
68   bool UsesBuffer(size_t used_binding_count, const Buffer* buffer) const;
69 
70  protected:
71   friend class base::RefCounted<IndexedBufferBindingHost>;
72 
73   virtual ~IndexedBufferBindingHost();
74 
75   // Whether this object is currently bound into the context.
76   bool is_bound_;
77 
78   // Whether or not to call Buffer::OnBind/OnUnbind whenever bindings change.
79   // This is only necessary for WebGL contexts to implement
80   // https://crbug.com/696345
81   bool do_buffer_refcounting_;
82 
83  private:
84   enum class IndexedBufferBindingType {
85     kBindBufferBase,
86     kBindBufferRange,
87     kBindBufferNone
88   };
89 
90   struct IndexedBufferBinding {
91     IndexedBufferBindingType type;
92     scoped_refptr<Buffer> buffer;
93 
94     // The following fields are only used if |type| is kBindBufferRange.
95     GLintptr offset;
96     GLsizeiptr size;
97     // The full buffer size at the last successful glBindBufferRange call.
98     GLsizeiptr effective_full_buffer_size;
99 
100     IndexedBufferBinding();
101     IndexedBufferBinding(const IndexedBufferBinding& other);
102     ~IndexedBufferBinding();
103 
104     bool operator==(const IndexedBufferBinding& other) const;
105 
106     void SetBindBufferBase(Buffer* _buffer);
107     void SetBindBufferRange(
108         Buffer* _buffer, GLintptr _offset, GLsizeiptr _size);
109     void Reset();
110   };
111 
112   // This is called when |needs_emulation_| is true, where the range
113   // (offset + size) can't go beyond the buffer's size.
114   static void DoAdjustedBindBufferRange(
115       GLenum target,
116       GLuint index,
117       GLuint service_id,
118       GLintptr offset,
119       GLsizeiptr size,
120       GLsizeiptr full_buffer_size,
121       bool round_down_uniform_bind_buffer_range_size);
122 
123   void UpdateMaxNonNullBindingIndex(size_t changed_index);
124 
125   std::vector<IndexedBufferBinding> buffer_bindings_;
126 
127   bool needs_emulation_;
128   bool round_down_uniform_bind_buffer_range_size_;
129 
130   // This is used for optimization purpose in context switching.
131   size_t max_non_null_binding_index_plus_one_;
132 
133   // The GL binding point that this host manages
134   // (e.g. GL_TRANSFORM_FEEDBACK_BUFFER).
135   GLenum target_;
136 };
137 
138 }  // namespace gles2
139 }  // namespace gpu
140 
141 #endif  // GPU_COMMAND_BUFFER_SERVICE_INDEXED_BUFFER_BINDING_HOST_H_
142