blob: 598620e464d09c1cfad69e1a9cf081ee9c887d63 [file] [log] [blame]
gman@chromium.orge39f7292012-01-04 20:06:471// Copyright (c) 2012 The Chromium Authors. All rights reserved.
gman@chromium.orga25fa872010-03-25 02:57:582// 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"
primiano05dadf012015-01-28 13:10:326
avif15d60a2015-12-21 17:06:337#include <stddef.h>
8#include <stdint.h>
9
ericrkb03ea3882016-11-04 23:08:4210#include "base/format_macros.h"
avi@chromium.orgf4390962013-06-11 07:29:2211#include "base/logging.h"
12#include "base/strings/stringprintf.h"
gabb23705312016-05-11 18:44:5613#include "base/threading/thread_task_runner_handle.h"
ericrka0399f4a2015-08-20 17:13:2914#include "base/trace_event/memory_dump_manager.h"
primiano05dadf012015-01-28 13:10:3215#include "base/trace_event/trace_event.h"
gman@chromium.orga25fa872010-03-25 02:57:5816#include "gpu/command_buffer/common/gles2_cmd_utils.h"
kbrc9f0e10c2015-03-31 19:49:1217#include "gpu/command_buffer/service/feature_info.h"
Kai Ninomiya821895e2017-06-06 00:03:2918#include "gpu/command_buffer/service/framebuffer_manager.h"
gman@chromium.orga25fa872010-03-25 02:57:5819#include "gpu/command_buffer/service/gles2_cmd_decoder.h"
ccameron@chromium.org00b192572012-07-28 04:00:2220#include "gpu/command_buffer/service/memory_tracking.h"
Kenneth Russell3b7911b2017-11-21 20:04:1621#include "gpu/command_buffer/service/texture_manager.h"
22#include "gpu/config/gpu_driver_bug_workarounds.h"
gman@chromium.org7989c9e2013-01-23 06:39:2623#include "ui/gl/gl_implementation.h"
martina.kollarova5511bade2015-08-06 17:34:1424#include "ui/gl/gl_version_info.h"
ericrka0399f4a2015-08-20 17:13:2925#include "ui/gl/trace_util.h"
gman@chromium.orga25fa872010-03-25 02:57:5826
27namespace gpu {
28namespace gles2 {
29
dyencb017312014-09-29 18:16:2030// This should contain everything to uniquely identify a Renderbuffer.
31static const char RenderbufferTag[] = "|Renderbuffer|";
32struct RenderbufferSignature {
33 GLenum internal_format_;
34 GLsizei samples_;
35 GLsizei width_;
36 GLsizei height_;
37
38 // Since we will be hashing this signature structure, the padding must be
39 // zero initialized. Although the C++11 specifications specify that this is
40 // true, we will use a constructor with a memset to further enforce it instead
41 // of relying on compilers adhering to this deep dark corner specification.
42 RenderbufferSignature(GLenum internal_format,
43 GLsizei samples,
44 GLsizei width,
45 GLsizei height) {
46 memset(this, 0, sizeof(RenderbufferSignature));
47 internal_format_ = internal_format;
48 samples_ = samples;
49 width_ = width;
50 height_ = height;
51 }
52};
53
ericrka0399f4a2015-08-20 17:13:2954RenderbufferManager::RenderbufferManager(MemoryTracker* memory_tracker,
55 GLint max_renderbuffer_size,
56 GLint max_samples,
57 FeatureInfo* feature_info)
58 : memory_type_tracker_(
ccamerondfb2f202015-10-09 23:17:5959 new MemoryTypeTracker(memory_tracker)),
ericrka0399f4a2015-08-20 17:13:2960 memory_tracker_(memory_tracker),
ccameron@chromium.org00b192572012-07-28 04:00:2261 max_renderbuffer_size_(max_renderbuffer_size),
gman@chromium.org0d6bfdc2011-11-02 01:32:2062 max_samples_(max_samples),
kbrc9f0e10c2015-03-31 19:49:1263 feature_info_(feature_info),
gman@chromium.orgfad1fee2011-12-23 01:06:4564 num_uncleared_renderbuffers_(0),
gman@chromium.orgee2a79c32013-03-10 03:50:2765 renderbuffer_count_(0),
gman@chromium.org80e4cfa02012-04-06 22:08:4566 have_context_(true) {
ericrka0399f4a2015-08-20 17:13:2967 // When created from InProcessCommandBuffer, we won't have a |memory_tracker_|
68 // so don't register a dump provider.
69 if (memory_tracker_) {
70 base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider(
primiano186d6bfe2015-10-30 13:21:4071 this, "gpu::RenderbufferManager", base::ThreadTaskRunnerHandle::Get());
ericrka0399f4a2015-08-20 17:13:2972 }
gman@chromium.org5094b0f2010-11-09 19:45:2473}
erg@google.combbf94a32010-10-13 17:44:1574
gman@chromium.orgd304cbd2010-07-01 22:41:1675RenderbufferManager::~RenderbufferManager() {
gman@chromium.orgee2a79c32013-03-10 03:50:2776 DCHECK(renderbuffers_.empty());
gman@chromium.org80e4cfa02012-04-06 22:08:4577 // If this triggers, that means something is keeping a reference to
gman@chromium.orged9f9cd2013-02-27 21:12:3578 // a Renderbuffer belonging to this.
gman@chromium.orgee2a79c32013-03-10 03:50:2779 CHECK_EQ(renderbuffer_count_, 0u);
gman@chromium.org5bd6feee2012-04-18 02:40:0380
81 DCHECK_EQ(0, num_uncleared_renderbuffers_);
ericrka0399f4a2015-08-20 17:13:2982
83 base::trace_event::MemoryDumpManager::GetInstance()->UnregisterDumpProvider(
84 this);
gman@chromium.orgd304cbd2010-07-01 22:41:1685}
86
gman@chromium.orged9f9cd2013-02-27 21:12:3587size_t Renderbuffer::EstimatedSize() {
avif15d60a2015-12-21 17:06:3388 uint32_t size = 0;
skyostil@chromium.org8e102e102013-09-20 22:50:2389 manager_->ComputeEstimatedRenderbufferSize(
gman@chromium.org7989c9e2013-01-23 06:39:2690 width_, height_, samples_, internal_format_, &size);
91 return size;
gman@chromium.orgfad1fee2011-12-23 01:06:4592}
93
dyencb017312014-09-29 18:16:2094
95size_t Renderbuffer::GetSignatureSize() const {
96 return sizeof(RenderbufferTag) + sizeof(RenderbufferSignature);
97}
98
Kai Ninomiya821895e2017-06-06 00:03:2999void Renderbuffer::SetInfoAndInvalidate(GLsizei samples,
100 GLenum internalformat,
101 GLsizei width,
102 GLsizei height) {
103 samples_ = samples;
104 internal_format_ = internalformat;
105 width_ = width;
106 height_ = height;
107 cleared_ = false;
Kenneth Russell8fab0ff2017-06-19 19:08:09108 allocated_ = true;
Kai Ninomiya821895e2017-06-06 00:03:29109 for (auto& point : framebuffer_attachment_points_) {
110 point.first->UnmarkAsComplete();
111 }
112}
113
dyencb017312014-09-29 18:16:20114void Renderbuffer::AddToSignature(std::string* signature) const {
gman@chromium.org73276522012-11-09 05:50:20115 DCHECK(signature);
dyencb017312014-09-29 18:16:20116 RenderbufferSignature signature_data(internal_format_,
117 samples_,
118 width_,
119 height_);
120
121 signature->append(RenderbufferTag, sizeof(RenderbufferTag));
122 signature->append(reinterpret_cast<const char*>(&signature_data),
123 sizeof(signature_data));
gman@chromium.org73276522012-11-09 05:50:20124}
125
piman@chromium.org62e65f02013-05-29 22:28:10126Renderbuffer::Renderbuffer(RenderbufferManager* manager,
127 GLuint client_id,
128 GLuint service_id)
gman@chromium.orged9f9cd2013-02-27 21:12:35129 : manager_(manager),
piman@chromium.org62e65f02013-05-29 22:28:10130 client_id_(client_id),
gman@chromium.orged9f9cd2013-02-27 21:12:35131 service_id_(service_id),
132 cleared_(true),
Kenneth Russell8fab0ff2017-06-19 19:08:09133 allocated_(false),
gman@chromium.orged9f9cd2013-02-27 21:12:35134 has_been_bound_(false),
135 samples_(0),
136 internal_format_(GL_RGBA4),
137 width_(0),
138 height_(0) {
139 manager_->StartTracking(this);
140}
141
Kenneth Russell3b7911b2017-11-21 20:04:16142bool Renderbuffer::RegenerateAndBindBackingObjectIfNeeded(
143 const GpuDriverBugWorkarounds& workarounds) {
144 // There are two workarounds which need this code path:
145 // depth_stencil_renderbuffer_resize_emulation
146 // multisample_renderbuffer_resize_emulation
147 bool multisample_workaround =
148 workarounds.multisample_renderbuffer_resize_emulation;
149 bool depth_stencil_workaround =
150 workarounds.depth_stencil_renderbuffer_resize_emulation;
151 if (!multisample_workaround && !depth_stencil_workaround) {
152 return false;
153 }
154
155 if (!allocated_ || !has_been_bound_) {
156 return false;
157 }
158
159 bool workaround_needed = (multisample_workaround && samples_ > 0) ||
160 (depth_stencil_workaround &&
161 TextureManager::ExtractFormatFromStorageFormat(
162 internal_format_) == GL_DEPTH_STENCIL);
163
164 if (!workaround_needed) {
Kenneth Russell8fab0ff2017-06-19 19:08:09165 return false;
166 }
167
168 GLint original_fbo = 0;
169 glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &original_fbo);
170
171 glDeleteRenderbuffersEXT(1, &service_id_);
172 service_id_ = 0;
173 glGenRenderbuffersEXT(1, &service_id_);
174 glBindRenderbufferEXT(GL_RENDERBUFFER, service_id_);
175
176 // Attach new renderbuffer to all framebuffers
177 for (auto& point : framebuffer_attachment_points_) {
178 glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER, point.first->service_id());
179 glFramebufferRenderbufferEXT(GL_DRAW_FRAMEBUFFER, point.second,
180 GL_RENDERBUFFER, service_id_);
181 }
182
183 glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER, original_fbo);
184
185 allocated_ = false;
186 return true;
187}
188
Kai Ninomiya821895e2017-06-06 00:03:29189void Renderbuffer::AddFramebufferAttachmentPoint(Framebuffer* framebuffer,
190 GLenum attachment) {
Kai Ninomiyaae213d062017-08-16 00:16:03191 DCHECK_NE(static_cast<GLenum>(GL_DEPTH_STENCIL_ATTACHMENT), attachment);
Kai Ninomiya821895e2017-06-06 00:03:29192 framebuffer_attachment_points_.insert(
193 std::make_pair(framebuffer, attachment));
194}
195
196void Renderbuffer::RemoveFramebufferAttachmentPoint(Framebuffer* framebuffer,
197 GLenum attachment) {
Kai Ninomiyaae213d062017-08-16 00:16:03198 DCHECK_NE(static_cast<GLenum>(GL_DEPTH_STENCIL_ATTACHMENT), attachment);
Kai Ninomiya821895e2017-06-06 00:03:29199 framebuffer_attachment_points_.erase(std::make_pair(framebuffer, attachment));
200}
201
gman@chromium.orged9f9cd2013-02-27 21:12:35202Renderbuffer::~Renderbuffer() {
gman@chromium.org3b675462012-01-19 05:20:56203 if (manager_) {
gman@chromium.org80e4cfa02012-04-06 22:08:45204 if (manager_->have_context_) {
205 GLuint id = service_id();
206 glDeleteRenderbuffersEXT(1, &id);
207 }
gman@chromium.org3b675462012-01-19 05:20:56208 manager_->StopTracking(this);
tzikddef02182018-08-14 07:08:33209 manager_ = nullptr;
gman@chromium.org3b675462012-01-19 05:20:56210 }
211}
212
gman@chromium.orgd304cbd2010-07-01 22:41:16213void RenderbufferManager::Destroy(bool have_context) {
gman@chromium.org80e4cfa02012-04-06 22:08:45214 have_context_ = have_context;
gman@chromium.orgee2a79c32013-03-10 03:50:27215 renderbuffers_.clear();
ericrka0399f4a2015-08-20 17:13:29216 DCHECK_EQ(0u, memory_type_tracker_->GetMemRepresented());
gman@chromium.orgd304cbd2010-07-01 22:41:16217}
218
gman@chromium.orged9f9cd2013-02-27 21:12:35219void RenderbufferManager::StartTracking(Renderbuffer* /* renderbuffer */) {
gman@chromium.orgee2a79c32013-03-10 03:50:27220 ++renderbuffer_count_;
gman@chromium.org80e4cfa02012-04-06 22:08:45221}
222
gman@chromium.orged9f9cd2013-02-27 21:12:35223void RenderbufferManager::StopTracking(Renderbuffer* renderbuffer) {
gman@chromium.orgee2a79c32013-03-10 03:50:27224 --renderbuffer_count_;
gman@chromium.org3b675462012-01-19 05:20:56225 if (!renderbuffer->cleared()) {
226 --num_uncleared_renderbuffers_;
227 }
ericrka0399f4a2015-08-20 17:13:29228 memory_type_tracker_->TrackMemFree(renderbuffer->EstimatedSize());
gman@chromium.org3b675462012-01-19 05:20:56229}
230
Kai Ninomiya821895e2017-06-06 00:03:29231void RenderbufferManager::SetInfoAndInvalidate(Renderbuffer* renderbuffer,
232 GLsizei samples,
233 GLenum internalformat,
234 GLsizei width,
235 GLsizei height) {
gman@chromium.org0d6bfdc2011-11-02 01:32:20236 DCHECK(renderbuffer);
237 if (!renderbuffer->cleared()) {
238 --num_uncleared_renderbuffers_;
239 }
ericrka0399f4a2015-08-20 17:13:29240 memory_type_tracker_->TrackMemFree(renderbuffer->EstimatedSize());
Kai Ninomiya821895e2017-06-06 00:03:29241 renderbuffer->SetInfoAndInvalidate(samples, internalformat, width, height);
ericrka0399f4a2015-08-20 17:13:29242 memory_type_tracker_->TrackMemAlloc(renderbuffer->EstimatedSize());
gman@chromium.org0d6bfdc2011-11-02 01:32:20243 if (!renderbuffer->cleared()) {
244 ++num_uncleared_renderbuffers_;
245 }
246}
247
gman@chromium.orged9f9cd2013-02-27 21:12:35248void RenderbufferManager::SetCleared(Renderbuffer* renderbuffer,
jamesr@chromium.org60f22d32012-12-12 00:31:58249 bool cleared) {
gman@chromium.org0d6bfdc2011-11-02 01:32:20250 DCHECK(renderbuffer);
251 if (!renderbuffer->cleared()) {
252 --num_uncleared_renderbuffers_;
253 }
jamesr@chromium.org60f22d32012-12-12 00:31:58254 renderbuffer->set_cleared(cleared);
gman@chromium.org0d6bfdc2011-11-02 01:32:20255 if (!renderbuffer->cleared()) {
256 ++num_uncleared_renderbuffers_;
257 }
258}
259
gman@chromium.orged9f9cd2013-02-27 21:12:35260void RenderbufferManager::CreateRenderbuffer(
gman@chromium.orgae51d192010-04-27 00:48:03261 GLuint client_id, GLuint service_id) {
piman@chromium.org62e65f02013-05-29 22:28:10262 scoped_refptr<Renderbuffer> renderbuffer(
263 new Renderbuffer(this, client_id, service_id));
gman@chromium.orgee2a79c32013-03-10 03:50:27264 std::pair<RenderbufferMap::iterator, bool> result =
265 renderbuffers_.insert(std::make_pair(client_id, renderbuffer));
gman@chromium.orga25fa872010-03-25 02:57:58266 DCHECK(result.second);
gman@chromium.orgee2a79c32013-03-10 03:50:27267 if (!renderbuffer->cleared()) {
gman@chromium.org0d6bfdc2011-11-02 01:32:20268 ++num_uncleared_renderbuffers_;
269 }
gman@chromium.orga25fa872010-03-25 02:57:58270}
271
gman@chromium.orged9f9cd2013-02-27 21:12:35272Renderbuffer* RenderbufferManager::GetRenderbuffer(
gman@chromium.orgae51d192010-04-27 00:48:03273 GLuint client_id) {
gman@chromium.orgee2a79c32013-03-10 03:50:27274 RenderbufferMap::iterator it = renderbuffers_.find(client_id);
tzikddef02182018-08-14 07:08:33275 return it != renderbuffers_.end() ? it->second.get() : nullptr;
gman@chromium.orga25fa872010-03-25 02:57:58276}
277
gman@chromium.orged9f9cd2013-02-27 21:12:35278void RenderbufferManager::RemoveRenderbuffer(GLuint client_id) {
gman@chromium.orgee2a79c32013-03-10 03:50:27279 RenderbufferMap::iterator it = renderbuffers_.find(client_id);
280 if (it != renderbuffers_.end()) {
rsleevi@chromium.org7cd76fd2013-06-02 21:11:11281 Renderbuffer* renderbuffer = it->second.get();
gman@chromium.orgee2a79c32013-03-10 03:50:27282 renderbuffer->MarkAsDeleted();
283 renderbuffers_.erase(it);
gman@chromium.orga25fa872010-03-25 02:57:58284 }
285}
286
avif15d60a2015-12-21 17:06:33287bool RenderbufferManager::ComputeEstimatedRenderbufferSize(
288 int width,
289 int height,
290 int samples,
291 int internal_format,
292 uint32_t* size) const {
gman@chromium.org7989c9e2013-01-23 06:39:26293 DCHECK(size);
294
avif15d60a2015-12-21 17:06:33295 uint32_t temp = 0;
gman@chromium.org7989c9e2013-01-23 06:39:26296 if (!SafeMultiplyUint32(width, height, &temp)) {
297 return false;
298 }
zmoa8e5d2e32016-05-31 23:16:54299 if (!SafeMultiplyUint32(temp, (samples == 0 ? 1 : samples), &temp)) {
gman@chromium.org7989c9e2013-01-23 06:39:26300 return false;
301 }
302 GLenum impl_format = InternalRenderbufferFormatToImplFormat(internal_format);
303 if (!SafeMultiplyUint32(
304 temp, GLES2Util::RenderbufferBytesPerPixel(impl_format), &temp)) {
305 return false;
306 }
307 *size = temp;
308 return true;
309}
310
311GLenum RenderbufferManager::InternalRenderbufferFormatToImplFormat(
skyostil@chromium.org8e102e102013-09-20 22:50:23312 GLenum impl_format) const {
kbrc9f0e10c2015-03-31 19:49:12313 if (!feature_info_->gl_version_info().BehavesLikeGLES()) {
gman@chromium.org7989c9e2013-01-23 06:39:26314 switch (impl_format) {
315 case GL_DEPTH_COMPONENT16:
316 return GL_DEPTH_COMPONENT;
317 case GL_RGBA4:
318 case GL_RGB5_A1:
319 return GL_RGBA;
320 case GL_RGB565:
321 return GL_RGB;
322 }
skyostil@chromium.org8e102e102013-09-20 22:50:23323 } else {
324 // Upgrade 16-bit depth to 24-bit if possible.
kbrc9f0e10c2015-03-31 19:49:12325 if (impl_format == GL_DEPTH_COMPONENT16 &&
326 feature_info_->feature_flags().oes_depth24)
skyostil@chromium.org8e102e102013-09-20 22:50:23327 return GL_DEPTH_COMPONENT24;
gman@chromium.org7989c9e2013-01-23 06:39:26328 }
329 return impl_format;
330}
331
ericrka0399f4a2015-08-20 17:13:29332bool RenderbufferManager::OnMemoryDump(
333 const base::trace_event::MemoryDumpArgs& args,
334 base::trace_event::ProcessMemoryDump* pmd) {
ericrkeff776982016-11-03 21:37:31335 using base::trace_event::MemoryAllocatorDump;
336 using base::trace_event::MemoryDumpLevelOfDetail;
ericrkb03ea3882016-11-04 23:08:42337 const uint64_t share_group_tracing_guid =
338 memory_tracker_->ShareGroupTracingGUID();
ericrkeff776982016-11-03 21:37:31339
340 if (args.level_of_detail == MemoryDumpLevelOfDetail::BACKGROUND) {
ericrkb03ea3882016-11-04 23:08:42341 std::string dump_name =
erikchen3158c942017-06-19 23:43:00342 base::StringPrintf("gpu/gl/renderbuffers/share_group_0x%" PRIX64,
ericrkb03ea3882016-11-04 23:08:42343 share_group_tracing_guid);
ericrkeff776982016-11-03 21:37:31344 MemoryAllocatorDump* dump = pmd->CreateAllocatorDump(dump_name);
345 dump->AddScalar(MemoryAllocatorDump::kNameSize,
346 MemoryAllocatorDump::kUnitsBytes, mem_represented());
347
348 // Early out, no need for more detail in a BACKGROUND dump.
349 return true;
350 }
351
ericrka0399f4a2015-08-20 17:13:29352 for (const auto& renderbuffer_entry : renderbuffers_) {
353 const auto& client_renderbuffer_id = renderbuffer_entry.first;
354 const auto& renderbuffer = renderbuffer_entry.second;
355
erikchen3158c942017-06-19 23:43:00356 std::string dump_name =
357 base::StringPrintf("gpu/gl/renderbuffers/share_group_0x%" PRIX64
358 "/renderbuffer_0x%" PRIX32,
359 share_group_tracing_guid, client_renderbuffer_id);
ericrkeff776982016-11-03 21:37:31360 MemoryAllocatorDump* dump = pmd->CreateAllocatorDump(dump_name);
361 dump->AddScalar(MemoryAllocatorDump::kNameSize,
362 MemoryAllocatorDump::kUnitsBytes,
ericrka0399f4a2015-08-20 17:13:29363 static_cast<uint64_t>(renderbuffer->EstimatedSize()));
364
ericrkb03ea3882016-11-04 23:08:42365 auto guid = gl::GetGLRenderbufferGUIDForTracing(share_group_tracing_guid,
366 client_renderbuffer_id);
ericrka0399f4a2015-08-20 17:13:29367 pmd->CreateSharedGlobalAllocatorDump(guid);
368 pmd->AddOwnershipEdge(dump->guid(), guid);
369 }
ericrkeff776982016-11-03 21:37:31370
ericrka0399f4a2015-08-20 17:13:29371 return true;
372}
373
gman@chromium.orga25fa872010-03-25 02:57:58374} // namespace gles2
375} // namespace gpu