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
3 // found in the LICENSE file.
4
5 #include "gpu/command_buffer/service/context_group.h"
6
7 #include <algorithm>
8 #include <string>
9
10 #include "base/command_line.h"
11 #include "base/strings/string_util.h"
12 #include "base/sys_info.h"
13 #include "gpu/command_buffer/common/id_allocator.h"
14 #include "gpu/command_buffer/service/buffer_manager.h"
15 #include "gpu/command_buffer/service/framebuffer_manager.h"
16 #include "gpu/command_buffer/service/gles2_cmd_decoder.h"
17 #include "gpu/command_buffer/service/gpu_switches.h"
18 #include "gpu/command_buffer/service/image_manager.h"
19 #include "gpu/command_buffer/service/mailbox_manager.h"
20 #include "gpu/command_buffer/service/memory_tracking.h"
21 #include "gpu/command_buffer/service/program_manager.h"
22 #include "gpu/command_buffer/service/renderbuffer_manager.h"
23 #include "gpu/command_buffer/service/shader_manager.h"
24 #include "gpu/command_buffer/service/texture_manager.h"
25 #include "gpu/command_buffer/service/transfer_buffer_manager.h"
26 #include "ui/gl/gl_implementation.h"
27
28 namespace gpu {
29 namespace gles2 {
30
ContextGroup(MailboxManager * mailbox_manager,ImageManager * image_manager,MemoryTracker * memory_tracker,StreamTextureManager * stream_texture_manager,FeatureInfo * feature_info,bool bind_generates_resource)31 ContextGroup::ContextGroup(
32 MailboxManager* mailbox_manager,
33 ImageManager* image_manager,
34 MemoryTracker* memory_tracker,
35 StreamTextureManager* stream_texture_manager,
36 FeatureInfo* feature_info,
37 bool bind_generates_resource)
38 : mailbox_manager_(mailbox_manager ? mailbox_manager : new MailboxManager),
39 image_manager_(image_manager ? image_manager : new ImageManager),
40 memory_tracker_(memory_tracker),
41 stream_texture_manager_(stream_texture_manager),
42 enforce_gl_minimums_(CommandLine::ForCurrentProcess()->HasSwitch(
43 switches::kEnforceGLMinimums)),
44 bind_generates_resource_(bind_generates_resource),
45 max_vertex_attribs_(0u),
46 max_texture_units_(0u),
47 max_texture_image_units_(0u),
48 max_vertex_texture_image_units_(0u),
49 max_fragment_uniform_vectors_(0u),
50 max_varying_vectors_(0u),
51 max_vertex_uniform_vectors_(0u),
52 max_color_attachments_(1u),
53 max_draw_buffers_(1u),
54 program_cache_(NULL),
55 feature_info_(feature_info ? feature_info : new FeatureInfo),
56 draw_buffer_(GL_BACK) {
57 {
58 TransferBufferManager* manager = new TransferBufferManager();
59 transfer_buffer_manager_.reset(manager);
60 manager->Initialize();
61 }
62
63 id_namespaces_[id_namespaces::kBuffers].reset(new IdAllocator);
64 id_namespaces_[id_namespaces::kFramebuffers].reset(new IdAllocator);
65 id_namespaces_[id_namespaces::kProgramsAndShaders].reset(
66 new NonReusedIdAllocator);
67 id_namespaces_[id_namespaces::kRenderbuffers].reset(new IdAllocator);
68 id_namespaces_[id_namespaces::kTextures].reset(new IdAllocator);
69 id_namespaces_[id_namespaces::kQueries].reset(new IdAllocator);
70 id_namespaces_[id_namespaces::kVertexArrays].reset(new IdAllocator);
71 }
72
GetIntegerv(GLenum pname,uint32 * var)73 static void GetIntegerv(GLenum pname, uint32* var) {
74 GLint value = 0;
75 glGetIntegerv(pname, &value);
76 *var = value;
77 }
78
Initialize(GLES2Decoder * decoder,const DisallowedFeatures & disallowed_features)79 bool ContextGroup::Initialize(
80 GLES2Decoder* decoder,
81 const DisallowedFeatures& disallowed_features) {
82 // If we've already initialized the group just add the context.
83 if (HaveContexts()) {
84 decoders_.push_back(base::AsWeakPtr<GLES2Decoder>(decoder));
85 return true;
86 }
87
88 if (!feature_info_->Initialize(disallowed_features)) {
89 LOG(ERROR) << "ContextGroup::Initialize failed because FeatureInfo "
90 << "initialization failed.";
91 return false;
92 }
93
94 const GLint kMinRenderbufferSize = 512; // GL says 1 pixel!
95 GLint max_renderbuffer_size = 0;
96 if (!QueryGLFeature(
97 GL_MAX_RENDERBUFFER_SIZE, kMinRenderbufferSize,
98 &max_renderbuffer_size)) {
99 LOG(ERROR) << "ContextGroup::Initialize failed because maximum "
100 << "renderbuffer size too small.";
101 return false;
102 }
103 GLint max_samples = 0;
104 if (feature_info_->feature_flags().chromium_framebuffer_multisample ||
105 feature_info_->feature_flags().multisampled_render_to_texture) {
106 if (feature_info_->feature_flags(
107 ).use_img_for_multisampled_render_to_texture) {
108 glGetIntegerv(GL_MAX_SAMPLES_IMG, &max_samples);
109 } else {
110 glGetIntegerv(GL_MAX_SAMPLES, &max_samples);
111 }
112 }
113
114 if (feature_info_->feature_flags().ext_draw_buffers) {
115 GetIntegerv(GL_MAX_COLOR_ATTACHMENTS_EXT, &max_color_attachments_);
116 if (max_color_attachments_ < 1)
117 max_color_attachments_ = 1;
118 GetIntegerv(GL_MAX_DRAW_BUFFERS_ARB, &max_draw_buffers_);
119 if (max_draw_buffers_ < 1)
120 max_draw_buffers_ = 1;
121 draw_buffer_ = GL_BACK;
122 }
123
124 const bool depth24_supported = feature_info_->feature_flags().oes_depth24;
125
126 buffer_manager_.reset(
127 new BufferManager(memory_tracker_.get(), feature_info_.get()));
128 framebuffer_manager_.reset(
129 new FramebufferManager(max_draw_buffers_, max_color_attachments_));
130 renderbuffer_manager_.reset(new RenderbufferManager(
131 memory_tracker_.get(), max_renderbuffer_size, max_samples,
132 depth24_supported));
133 shader_manager_.reset(new ShaderManager());
134
135 // Lookup GL things we need to know.
136 const GLint kGLES2RequiredMinimumVertexAttribs = 8u;
137 if (!QueryGLFeatureU(
138 GL_MAX_VERTEX_ATTRIBS, kGLES2RequiredMinimumVertexAttribs,
139 &max_vertex_attribs_)) {
140 LOG(ERROR) << "ContextGroup::Initialize failed because too few "
141 << "vertex attributes supported.";
142 return false;
143 }
144
145 const GLuint kGLES2RequiredMinimumTextureUnits = 8u;
146 if (!QueryGLFeatureU(
147 GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, kGLES2RequiredMinimumTextureUnits,
148 &max_texture_units_)) {
149 LOG(ERROR) << "ContextGroup::Initialize failed because too few "
150 << "texture units supported.";
151 return false;
152 }
153
154 GLint max_texture_size = 0;
155 GLint max_cube_map_texture_size = 0;
156 const GLint kMinTextureSize = 2048; // GL actually says 64!?!?
157 const GLint kMinCubeMapSize = 256; // GL actually says 16!?!?
158 if (!QueryGLFeature(
159 GL_MAX_TEXTURE_SIZE, kMinTextureSize, &max_texture_size) ||
160 !QueryGLFeature(
161 GL_MAX_CUBE_MAP_TEXTURE_SIZE, kMinCubeMapSize,
162 &max_cube_map_texture_size)) {
163 LOG(ERROR) << "ContextGroup::Initialize failed because maximum texture size"
164 << "is too small.";
165 return false;
166 }
167
168 if (feature_info_->workarounds().max_texture_size) {
169 max_texture_size = std::min(
170 max_texture_size, feature_info_->workarounds().max_texture_size);
171 }
172 if (feature_info_->workarounds().max_cube_map_texture_size) {
173 max_cube_map_texture_size = std::min(
174 max_cube_map_texture_size,
175 feature_info_->workarounds().max_cube_map_texture_size);
176 }
177
178 texture_manager_.reset(new TextureManager(memory_tracker_.get(),
179 feature_info_.get(),
180 max_texture_size,
181 max_cube_map_texture_size));
182 texture_manager_->set_framebuffer_manager(framebuffer_manager_.get());
183 texture_manager_->set_stream_texture_manager(stream_texture_manager_);
184
185 const GLint kMinTextureImageUnits = 8;
186 const GLint kMinVertexTextureImageUnits = 0;
187 if (!QueryGLFeatureU(
188 GL_MAX_TEXTURE_IMAGE_UNITS, kMinTextureImageUnits,
189 &max_texture_image_units_) ||
190 !QueryGLFeatureU(
191 GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, kMinVertexTextureImageUnits,
192 &max_vertex_texture_image_units_)) {
193 LOG(ERROR) << "ContextGroup::Initialize failed because too few "
194 << "texture units.";
195 return false;
196 }
197
198 if (gfx::GetGLImplementation() == gfx::kGLImplementationEGLGLES2) {
199 GetIntegerv(GL_MAX_FRAGMENT_UNIFORM_VECTORS,
200 &max_fragment_uniform_vectors_);
201 GetIntegerv(GL_MAX_VARYING_VECTORS, &max_varying_vectors_);
202 GetIntegerv(GL_MAX_VERTEX_UNIFORM_VECTORS, &max_vertex_uniform_vectors_);
203 } else {
204 GetIntegerv(
205 GL_MAX_FRAGMENT_UNIFORM_COMPONENTS, &max_fragment_uniform_vectors_);
206 max_fragment_uniform_vectors_ /= 4;
207 GetIntegerv(GL_MAX_VARYING_FLOATS, &max_varying_vectors_);
208 max_varying_vectors_ /= 4;
209 GetIntegerv(GL_MAX_VERTEX_UNIFORM_COMPONENTS, &max_vertex_uniform_vectors_);
210 max_vertex_uniform_vectors_ /= 4;
211 }
212
213 const GLint kMinFragmentUniformVectors = 16;
214 const GLint kMinVaryingVectors = 8;
215 const GLint kMinVertexUniformVectors = 128;
216 if (!CheckGLFeatureU(
217 kMinFragmentUniformVectors, &max_fragment_uniform_vectors_) ||
218 !CheckGLFeatureU(kMinVaryingVectors, &max_varying_vectors_) ||
219 !CheckGLFeatureU(
220 kMinVertexUniformVectors, &max_vertex_uniform_vectors_)) {
221 LOG(ERROR) << "ContextGroup::Initialize failed because too few "
222 << "uniforms or varyings supported.";
223 return false;
224 }
225
226 // TODO(gman): Use workarounds similar to max_texture_size above to implement.
227 if (gfx::GetGLImplementation() == gfx::kGLImplementationOSMesaGL) {
228 // Some shaders in Skia needed more than the min.
229 max_fragment_uniform_vectors_ =
230 std::min(static_cast<uint32>(kMinFragmentUniformVectors * 2),
231 max_fragment_uniform_vectors_);
232 max_varying_vectors_ =
233 std::min(static_cast<uint32>(kMinVaryingVectors * 2),
234 max_varying_vectors_);
235 max_vertex_uniform_vectors_ =
236 std::min(static_cast<uint32>(kMinVertexUniformVectors * 2),
237 max_vertex_uniform_vectors_);
238 }
239
240 program_manager_.reset(new ProgramManager(
241 program_cache_, max_varying_vectors_));
242
243 if (!texture_manager_->Initialize()) {
244 LOG(ERROR) << "Context::Group::Initialize failed because texture manager "
245 << "failed to initialize.";
246 return false;
247 }
248
249 decoders_.push_back(base::AsWeakPtr<GLES2Decoder>(decoder));
250 return true;
251 }
252
253 namespace {
254
IsNull(const base::WeakPtr<gles2::GLES2Decoder> & decoder)255 bool IsNull(const base::WeakPtr<gles2::GLES2Decoder>& decoder) {
256 return !decoder.get();
257 }
258
259 template <typename T>
260 class WeakPtrEquals {
261 public:
WeakPtrEquals(T * t)262 explicit WeakPtrEquals(T* t) : t_(t) {}
263
operator ()(const base::WeakPtr<T> & t)264 bool operator()(const base::WeakPtr<T>& t) {
265 return t.get() == t_;
266 }
267
268 private:
269 T* const t_;
270 };
271
272 } // namespace anonymous
273
HaveContexts()274 bool ContextGroup::HaveContexts() {
275 decoders_.erase(std::remove_if(decoders_.begin(), decoders_.end(), IsNull),
276 decoders_.end());
277 return !decoders_.empty();
278 }
279
Destroy(GLES2Decoder * decoder,bool have_context)280 void ContextGroup::Destroy(GLES2Decoder* decoder, bool have_context) {
281 decoders_.erase(std::remove_if(decoders_.begin(), decoders_.end(),
282 WeakPtrEquals<gles2::GLES2Decoder>(decoder)),
283 decoders_.end());
284 // If we still have contexts do nothing.
285 if (HaveContexts()) {
286 return;
287 }
288
289 if (buffer_manager_ != NULL) {
290 buffer_manager_->Destroy(have_context);
291 buffer_manager_.reset();
292 }
293
294 if (framebuffer_manager_ != NULL) {
295 framebuffer_manager_->Destroy(have_context);
296 if (texture_manager_)
297 texture_manager_->set_framebuffer_manager(NULL);
298 framebuffer_manager_.reset();
299 }
300
301 if (renderbuffer_manager_ != NULL) {
302 renderbuffer_manager_->Destroy(have_context);
303 renderbuffer_manager_.reset();
304 }
305
306 if (texture_manager_ != NULL) {
307 texture_manager_->Destroy(have_context);
308 texture_manager_.reset();
309 }
310
311 if (program_manager_ != NULL) {
312 program_manager_->Destroy(have_context);
313 program_manager_.reset();
314 }
315
316 if (shader_manager_ != NULL) {
317 shader_manager_->Destroy(have_context);
318 shader_manager_.reset();
319 }
320
321 memory_tracker_ = NULL;
322 stream_texture_manager_ = NULL;
323 }
324
GetIdAllocator(unsigned namespace_id)325 IdAllocatorInterface* ContextGroup::GetIdAllocator(unsigned namespace_id) {
326 if (namespace_id >= arraysize(id_namespaces_))
327 return NULL;
328
329 return id_namespaces_[namespace_id].get();
330 }
331
GetMemRepresented() const332 uint32 ContextGroup::GetMemRepresented() const {
333 uint32 total = 0;
334 if (buffer_manager_.get())
335 total += buffer_manager_->mem_represented();
336 if (renderbuffer_manager_.get())
337 total += renderbuffer_manager_->mem_represented();
338 if (texture_manager_.get())
339 total += texture_manager_->mem_represented();
340 return total;
341 }
342
LoseContexts(GLenum reset_status)343 void ContextGroup::LoseContexts(GLenum reset_status) {
344 for (size_t ii = 0; ii < decoders_.size(); ++ii) {
345 if (decoders_[ii].get()) {
346 decoders_[ii]->LoseContext(reset_status);
347 }
348 }
349 }
350
~ContextGroup()351 ContextGroup::~ContextGroup() {
352 CHECK(!HaveContexts());
353 }
354
CheckGLFeature(GLint min_required,GLint * v)355 bool ContextGroup::CheckGLFeature(GLint min_required, GLint* v) {
356 GLint value = *v;
357 if (enforce_gl_minimums_) {
358 value = std::min(min_required, value);
359 }
360 *v = value;
361 return value >= min_required;
362 }
363
CheckGLFeatureU(GLint min_required,uint32 * v)364 bool ContextGroup::CheckGLFeatureU(GLint min_required, uint32* v) {
365 GLint value = *v;
366 if (enforce_gl_minimums_) {
367 value = std::min(min_required, value);
368 }
369 *v = value;
370 return value >= min_required;
371 }
372
QueryGLFeature(GLenum pname,GLint min_required,GLint * v)373 bool ContextGroup::QueryGLFeature(
374 GLenum pname, GLint min_required, GLint* v) {
375 GLint value = 0;
376 glGetIntegerv(pname, &value);
377 *v = value;
378 return CheckGLFeature(min_required, v);
379 }
380
QueryGLFeatureU(GLenum pname,GLint min_required,uint32 * v)381 bool ContextGroup::QueryGLFeatureU(
382 GLenum pname, GLint min_required, uint32* v) {
383 uint32 value = 0;
384 GetIntegerv(pname, &value);
385 bool result = CheckGLFeatureU(min_required, &value);
386 *v = value;
387 return result;
388 }
389
390 } // namespace gles2
391 } // namespace gpu
392