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/renderbuffer_manager.h"
6#include "base/debug/trace_event.h"
7#include "base/logging.h"
8#include "base/strings/stringprintf.h"
9#include "gpu/command_buffer/common/gles2_cmd_utils.h"
10#include "gpu/command_buffer/service/gles2_cmd_decoder.h"
11#include "gpu/command_buffer/service/memory_tracking.h"
12#include "ui/gl/gl_implementation.h"
13
14namespace gpu {
15namespace gles2 {
16
17RenderbufferManager::RenderbufferManager(
18    MemoryTracker* memory_tracker,
19    GLint max_renderbuffer_size,
20    GLint max_samples,
21    bool depth24_supported)
22    : memory_tracker_(
23          new MemoryTypeTracker(memory_tracker, MemoryTracker::kUnmanaged)),
24      max_renderbuffer_size_(max_renderbuffer_size),
25      max_samples_(max_samples),
26      depth24_supported_(depth24_supported),
27      num_uncleared_renderbuffers_(0),
28      renderbuffer_count_(0),
29      have_context_(true) {
30}
31
32RenderbufferManager::~RenderbufferManager() {
33  DCHECK(renderbuffers_.empty());
34  // If this triggers, that means something is keeping a reference to
35  // a Renderbuffer belonging to this.
36  CHECK_EQ(renderbuffer_count_, 0u);
37
38  DCHECK_EQ(0, num_uncleared_renderbuffers_);
39}
40
41size_t Renderbuffer::EstimatedSize() {
42  uint32 size = 0;
43  manager_->ComputeEstimatedRenderbufferSize(
44      width_, height_, samples_, internal_format_, &size);
45  return size;
46}
47
48void Renderbuffer::AddToSignature(
49    std::string* signature) const {
50  DCHECK(signature);
51  *signature += base::StringPrintf(
52      "|Renderbuffer|internal_format=%04x|samples=%d|width=%d|height=%d",
53      internal_format_, samples_, width_, height_);
54}
55
56Renderbuffer::Renderbuffer(RenderbufferManager* manager,
57                           GLuint client_id,
58                           GLuint service_id)
59    : manager_(manager),
60      client_id_(client_id),
61      service_id_(service_id),
62      cleared_(true),
63      has_been_bound_(false),
64      samples_(0),
65      internal_format_(GL_RGBA4),
66      width_(0),
67      height_(0) {
68  manager_->StartTracking(this);
69}
70
71Renderbuffer::~Renderbuffer() {
72  if (manager_) {
73    if (manager_->have_context_) {
74      GLuint id = service_id();
75      glDeleteRenderbuffersEXT(1, &id);
76    }
77    manager_->StopTracking(this);
78    manager_ = NULL;
79  }
80}
81
82void RenderbufferManager::Destroy(bool have_context) {
83  have_context_ = have_context;
84  renderbuffers_.clear();
85  DCHECK_EQ(0u, memory_tracker_->GetMemRepresented());
86}
87
88void RenderbufferManager::StartTracking(Renderbuffer* /* renderbuffer */) {
89  ++renderbuffer_count_;
90}
91
92void RenderbufferManager::StopTracking(Renderbuffer* renderbuffer) {
93  --renderbuffer_count_;
94  if (!renderbuffer->cleared()) {
95    --num_uncleared_renderbuffers_;
96  }
97  memory_tracker_->TrackMemFree(renderbuffer->EstimatedSize());
98}
99
100void RenderbufferManager::SetInfo(
101    Renderbuffer* renderbuffer,
102    GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height) {
103  DCHECK(renderbuffer);
104  if (!renderbuffer->cleared()) {
105    --num_uncleared_renderbuffers_;
106  }
107  memory_tracker_->TrackMemFree(renderbuffer->EstimatedSize());
108  renderbuffer->SetInfo(samples, internalformat, width, height);
109  memory_tracker_->TrackMemAlloc(renderbuffer->EstimatedSize());
110  if (!renderbuffer->cleared()) {
111    ++num_uncleared_renderbuffers_;
112  }
113}
114
115void RenderbufferManager::SetCleared(Renderbuffer* renderbuffer,
116                                     bool cleared) {
117  DCHECK(renderbuffer);
118  if (!renderbuffer->cleared()) {
119    --num_uncleared_renderbuffers_;
120  }
121  renderbuffer->set_cleared(cleared);
122  if (!renderbuffer->cleared()) {
123    ++num_uncleared_renderbuffers_;
124  }
125}
126
127void RenderbufferManager::CreateRenderbuffer(
128    GLuint client_id, GLuint service_id) {
129  scoped_refptr<Renderbuffer> renderbuffer(
130      new Renderbuffer(this, client_id, service_id));
131  std::pair<RenderbufferMap::iterator, bool> result =
132      renderbuffers_.insert(std::make_pair(client_id, renderbuffer));
133  DCHECK(result.second);
134  if (!renderbuffer->cleared()) {
135    ++num_uncleared_renderbuffers_;
136  }
137}
138
139Renderbuffer* RenderbufferManager::GetRenderbuffer(
140    GLuint client_id) {
141  RenderbufferMap::iterator it = renderbuffers_.find(client_id);
142  return it != renderbuffers_.end() ? it->second.get() : NULL;
143}
144
145void RenderbufferManager::RemoveRenderbuffer(GLuint client_id) {
146  RenderbufferMap::iterator it = renderbuffers_.find(client_id);
147  if (it != renderbuffers_.end()) {
148    Renderbuffer* renderbuffer = it->second.get();
149    renderbuffer->MarkAsDeleted();
150    renderbuffers_.erase(it);
151  }
152}
153
154bool RenderbufferManager::ComputeEstimatedRenderbufferSize(int width,
155                                                           int height,
156                                                           int samples,
157                                                           int internal_format,
158                                                           uint32* size) const {
159  DCHECK(size);
160
161  uint32 temp = 0;
162  if (!SafeMultiplyUint32(width, height, &temp)) {
163    return false;
164  }
165  if (!SafeMultiplyUint32(temp, samples, &temp)) {
166    return false;
167  }
168  GLenum impl_format = InternalRenderbufferFormatToImplFormat(internal_format);
169  if (!SafeMultiplyUint32(
170      temp, GLES2Util::RenderbufferBytesPerPixel(impl_format), &temp)) {
171    return false;
172  }
173  *size = temp;
174  return true;
175}
176
177GLenum RenderbufferManager::InternalRenderbufferFormatToImplFormat(
178    GLenum impl_format) const {
179  if (gfx::GetGLImplementation() != gfx::kGLImplementationEGLGLES2) {
180    switch (impl_format) {
181      case GL_DEPTH_COMPONENT16:
182        return GL_DEPTH_COMPONENT;
183      case GL_RGBA4:
184      case GL_RGB5_A1:
185        return GL_RGBA;
186      case GL_RGB565:
187        return GL_RGB;
188    }
189  } else {
190    // Upgrade 16-bit depth to 24-bit if possible.
191    if (impl_format == GL_DEPTH_COMPONENT16 && depth24_supported_)
192      return GL_DEPTH_COMPONENT24;
193  }
194  return impl_format;
195}
196
197}  // namespace gles2
198}  // namespace gpu
199
200
201