blob: 8075cb3acf7204a661a6c094edc1c1a783d46dfb [file] [log] [blame]
Avi Drissman05dfbc822022-09-13 21:25:341// Copyright 2012 The Chromium Authors
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
gman@chromium.orga25fa872010-03-25 02:57:585#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
Hans Wennborg453400c2020-05-04 14:04:3710#include "base/check_op.h"
Tom Sepezd8f7cade2025-07-22 16:48:0111#include "base/compiler_specific.h"
ericrkb03ea3882016-11-04 23:08:4212#include "base/format_macros.h"
avi@chromium.orgf4390962013-06-11 07:29:2213#include "base/strings/stringprintf.h"
Sean Maher5b9af51f2022-11-21 15:32:4714#include "base/task/single_thread_task_runner.h"
ericrka0399f4a2015-08-20 17:13:2915#include "base/trace_event/memory_dump_manager.h"
primiano05dadf012015-01-28 13:10:3216#include "base/trace_event/trace_event.h"
gman@chromium.orga25fa872010-03-25 02:57:5817#include "gpu/command_buffer/common/gles2_cmd_utils.h"
kbrc9f0e10c2015-03-31 19:49:1218#include "gpu/command_buffer/service/feature_info.h"
Kai Ninomiya821895e2017-06-06 00:03:2919#include "gpu/command_buffer/service/framebuffer_manager.h"
gman@chromium.orga25fa872010-03-25 02:57:5820#include "gpu/command_buffer/service/gles2_cmd_decoder.h"
ccameron@chromium.org00b192572012-07-28 04:00:2221#include "gpu/command_buffer/service/memory_tracking.h"
Kenneth Russell3b7911b2017-11-21 20:04:1622#include "gpu/command_buffer/service/texture_manager.h"
23#include "gpu/config/gpu_driver_bug_workarounds.h"
gman@chromium.org7989c9e2013-01-23 06:39:2624#include "ui/gl/gl_implementation.h"
martina.kollarova5511bade2015-08-06 17:34:1425#include "ui/gl/gl_version_info.h"
ericrka0399f4a2015-08-20 17:13:2926#include "ui/gl/trace_util.h"
gman@chromium.orga25fa872010-03-25 02:57:5827
28namespace gpu {
29namespace gles2 {
30
dyencb017312014-09-29 18:16:2031// This should contain everything to uniquely identify a Renderbuffer.
32static const char RenderbufferTag[] = "|Renderbuffer|";
33struct RenderbufferSignature {
34 GLenum internal_format_;
35 GLsizei samples_;
36 GLsizei width_;
37 GLsizei height_;
38
39 // Since we will be hashing this signature structure, the padding must be
40 // zero initialized. Although the C++11 specifications specify that this is
41 // true, we will use a constructor with a memset to further enforce it instead
42 // of relying on compilers adhering to this deep dark corner specification.
43 RenderbufferSignature(GLenum internal_format,
44 GLsizei samples,
45 GLsizei width,
46 GLsizei height) {
Tom Sepezd8f7cade2025-07-22 16:48:0147 UNSAFE_TODO(memset(this, 0, sizeof(RenderbufferSignature)));
dyencb017312014-09-29 18:16:2048 internal_format_ = internal_format;
49 samples_ = samples;
50 width_ = width;
51 height_ = height;
52 }
53};
54
Maggie Chen40af1efa2025-06-04 18:19:5755RenderbufferManager::RenderbufferManager(
56 scoped_refptr<MemoryTracker> memory_tracker,
57 GLint max_renderbuffer_size,
58 GLint max_samples,
59 FeatureInfo* feature_info)
60 : memory_type_tracker_(new MemoryTypeTracker(std::move(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.
Maggie Chen40af1efa2025-06-04 18:19:5769 if (memory_type_tracker_->memory_tracker()) {
ericrka0399f4a2015-08-20 17:13:2970 base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider(
Sean Maher5b9af51f2022-11-21 15:32:4771 this, "gpu::RenderbufferManager",
72 base::SingleThreadTaskRunner::GetCurrentDefault());
ericrka0399f4a2015-08-20 17:13:2973 }
gman@chromium.org5094b0f2010-11-09 19:45:2474}
erg@google.combbf94a32010-10-13 17:44:1575
gman@chromium.orgd304cbd2010-07-01 22:41:1676RenderbufferManager::~RenderbufferManager() {
gman@chromium.orgee2a79c32013-03-10 03:50:2777 DCHECK(renderbuffers_.empty());
gman@chromium.org80e4cfa02012-04-06 22:08:4578 // If this triggers, that means something is keeping a reference to
gman@chromium.orged9f9cd2013-02-27 21:12:3579 // a Renderbuffer belonging to this.
gman@chromium.orgee2a79c32013-03-10 03:50:2780 CHECK_EQ(renderbuffer_count_, 0u);
gman@chromium.org5bd6feee2012-04-18 02:40:0381
82 DCHECK_EQ(0, num_uncleared_renderbuffers_);
ericrka0399f4a2015-08-20 17:13:2983
84 base::trace_event::MemoryDumpManager::GetInstance()->UnregisterDumpProvider(
85 this);
gman@chromium.orgd304cbd2010-07-01 22:41:1686}
87
gman@chromium.orged9f9cd2013-02-27 21:12:3588size_t Renderbuffer::EstimatedSize() {
avif15d60a2015-12-21 17:06:3389 uint32_t size = 0;
skyostil@chromium.org8e102e102013-09-20 22:50:2390 manager_->ComputeEstimatedRenderbufferSize(
gman@chromium.org7989c9e2013-01-23 06:39:2691 width_, height_, samples_, internal_format_, &size);
92 return size;
gman@chromium.orgfad1fee2011-12-23 01:06:4593}
94
dyencb017312014-09-29 18:16:2095
96size_t Renderbuffer::GetSignatureSize() const {
97 return sizeof(RenderbufferTag) + sizeof(RenderbufferSignature);
98}
99
Kai Ninomiya821895e2017-06-06 00:03:29100void Renderbuffer::SetInfoAndInvalidate(GLsizei samples,
101 GLenum internalformat,
102 GLsizei width,
103 GLsizei height) {
104 samples_ = samples;
105 internal_format_ = internalformat;
106 width_ = width;
107 height_ = height;
108 cleared_ = false;
Kenneth Russell8fab0ff2017-06-19 19:08:09109 allocated_ = true;
Kai Ninomiya821895e2017-06-06 00:03:29110 for (auto& point : framebuffer_attachment_points_) {
111 point.first->UnmarkAsComplete();
112 }
113}
114
dyencb017312014-09-29 18:16:20115void Renderbuffer::AddToSignature(std::string* signature) const {
gman@chromium.org73276522012-11-09 05:50:20116 DCHECK(signature);
dyencb017312014-09-29 18:16:20117 RenderbufferSignature signature_data(internal_format_,
118 samples_,
119 width_,
120 height_);
121
122 signature->append(RenderbufferTag, sizeof(RenderbufferTag));
123 signature->append(reinterpret_cast<const char*>(&signature_data),
124 sizeof(signature_data));
gman@chromium.org73276522012-11-09 05:50:20125}
126
piman@chromium.org62e65f02013-05-29 22:28:10127Renderbuffer::Renderbuffer(RenderbufferManager* manager,
128 GLuint client_id,
129 GLuint service_id)
gman@chromium.orged9f9cd2013-02-27 21:12:35130 : manager_(manager),
piman@chromium.org62e65f02013-05-29 22:28:10131 client_id_(client_id),
gman@chromium.orged9f9cd2013-02-27 21:12:35132 service_id_(service_id),
133 cleared_(true),
Kenneth Russell8fab0ff2017-06-19 19:08:09134 allocated_(false),
gman@chromium.orged9f9cd2013-02-27 21:12:35135 has_been_bound_(false),
136 samples_(0),
137 internal_format_(GL_RGBA4),
138 width_(0),
139 height_(0) {
140 manager_->StartTracking(this);
141}
142
Kenneth Russell3b7911b2017-11-21 20:04:16143bool Renderbuffer::RegenerateAndBindBackingObjectIfNeeded(
144 const GpuDriverBugWorkarounds& workarounds) {
Kenneth Russell3b7911b2017-11-21 20:04:16145 bool multisample_workaround =
146 workarounds.multisample_renderbuffer_resize_emulation;
Zhenyao Moe2c28492023-09-16 12:20:52147 if (!multisample_workaround) {
Kenneth Russell3b7911b2017-11-21 20:04:16148 return false;
149 }
150
151 if (!allocated_ || !has_been_bound_) {
152 return false;
153 }
154
Zhenyao Moe2c28492023-09-16 12:20:52155 bool workaround_needed = (multisample_workaround && samples_ > 0);
Kenneth Russell3b7911b2017-11-21 20:04:16156 if (!workaround_needed) {
Kenneth Russell8fab0ff2017-06-19 19:08:09157 return false;
158 }
159
160 GLint original_fbo = 0;
161 glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &original_fbo);
162
163 glDeleteRenderbuffersEXT(1, &service_id_);
164 service_id_ = 0;
165 glGenRenderbuffersEXT(1, &service_id_);
166 glBindRenderbufferEXT(GL_RENDERBUFFER, service_id_);
167
168 // Attach new renderbuffer to all framebuffers
169 for (auto& point : framebuffer_attachment_points_) {
170 glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER, point.first->service_id());
171 glFramebufferRenderbufferEXT(GL_DRAW_FRAMEBUFFER, point.second,
172 GL_RENDERBUFFER, service_id_);
173 }
174
175 glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER, original_fbo);
176
177 allocated_ = false;
178 return true;
179}
180
Kai Ninomiya821895e2017-06-06 00:03:29181void Renderbuffer::AddFramebufferAttachmentPoint(Framebuffer* framebuffer,
182 GLenum attachment) {
Kai Ninomiyaae213d062017-08-16 00:16:03183 DCHECK_NE(static_cast<GLenum>(GL_DEPTH_STENCIL_ATTACHMENT), attachment);
Kai Ninomiya821895e2017-06-06 00:03:29184 framebuffer_attachment_points_.insert(
185 std::make_pair(framebuffer, attachment));
186}
187
188void Renderbuffer::RemoveFramebufferAttachmentPoint(Framebuffer* framebuffer,
189 GLenum attachment) {
Kai Ninomiyaae213d062017-08-16 00:16:03190 DCHECK_NE(static_cast<GLenum>(GL_DEPTH_STENCIL_ATTACHMENT), attachment);
Kai Ninomiya821895e2017-06-06 00:03:29191 framebuffer_attachment_points_.erase(std::make_pair(framebuffer, attachment));
192}
193
gman@chromium.orged9f9cd2013-02-27 21:12:35194Renderbuffer::~Renderbuffer() {
gman@chromium.org3b675462012-01-19 05:20:56195 if (manager_) {
gman@chromium.org80e4cfa02012-04-06 22:08:45196 if (manager_->have_context_) {
197 GLuint id = service_id();
198 glDeleteRenderbuffersEXT(1, &id);
199 }
gman@chromium.org3b675462012-01-19 05:20:56200 manager_->StopTracking(this);
tzikddef02182018-08-14 07:08:33201 manager_ = nullptr;
gman@chromium.org3b675462012-01-19 05:20:56202 }
203}
204
gman@chromium.orgd304cbd2010-07-01 22:41:16205void RenderbufferManager::Destroy(bool have_context) {
gman@chromium.org80e4cfa02012-04-06 22:08:45206 have_context_ = have_context;
gman@chromium.orgee2a79c32013-03-10 03:50:27207 renderbuffers_.clear();
ericrka0399f4a2015-08-20 17:13:29208 DCHECK_EQ(0u, memory_type_tracker_->GetMemRepresented());
gman@chromium.orgd304cbd2010-07-01 22:41:16209}
210
gman@chromium.orged9f9cd2013-02-27 21:12:35211void RenderbufferManager::StartTracking(Renderbuffer* /* renderbuffer */) {
gman@chromium.orgee2a79c32013-03-10 03:50:27212 ++renderbuffer_count_;
gman@chromium.org80e4cfa02012-04-06 22:08:45213}
214
gman@chromium.orged9f9cd2013-02-27 21:12:35215void RenderbufferManager::StopTracking(Renderbuffer* renderbuffer) {
gman@chromium.orgee2a79c32013-03-10 03:50:27216 --renderbuffer_count_;
gman@chromium.org3b675462012-01-19 05:20:56217 if (!renderbuffer->cleared()) {
218 --num_uncleared_renderbuffers_;
219 }
ericrka0399f4a2015-08-20 17:13:29220 memory_type_tracker_->TrackMemFree(renderbuffer->EstimatedSize());
gman@chromium.org3b675462012-01-19 05:20:56221}
222
Kai Ninomiya821895e2017-06-06 00:03:29223void RenderbufferManager::SetInfoAndInvalidate(Renderbuffer* renderbuffer,
224 GLsizei samples,
225 GLenum internalformat,
226 GLsizei width,
227 GLsizei height) {
gman@chromium.org0d6bfdc2011-11-02 01:32:20228 DCHECK(renderbuffer);
229 if (!renderbuffer->cleared()) {
230 --num_uncleared_renderbuffers_;
231 }
ericrka0399f4a2015-08-20 17:13:29232 memory_type_tracker_->TrackMemFree(renderbuffer->EstimatedSize());
Kai Ninomiya821895e2017-06-06 00:03:29233 renderbuffer->SetInfoAndInvalidate(samples, internalformat, width, height);
ericrka0399f4a2015-08-20 17:13:29234 memory_type_tracker_->TrackMemAlloc(renderbuffer->EstimatedSize());
gman@chromium.org0d6bfdc2011-11-02 01:32:20235 if (!renderbuffer->cleared()) {
236 ++num_uncleared_renderbuffers_;
237 }
238}
239
gman@chromium.orged9f9cd2013-02-27 21:12:35240void RenderbufferManager::SetCleared(Renderbuffer* renderbuffer,
jamesr@chromium.org60f22d32012-12-12 00:31:58241 bool cleared) {
gman@chromium.org0d6bfdc2011-11-02 01:32:20242 DCHECK(renderbuffer);
243 if (!renderbuffer->cleared()) {
244 --num_uncleared_renderbuffers_;
245 }
jamesr@chromium.org60f22d32012-12-12 00:31:58246 renderbuffer->set_cleared(cleared);
gman@chromium.org0d6bfdc2011-11-02 01:32:20247 if (!renderbuffer->cleared()) {
248 ++num_uncleared_renderbuffers_;
249 }
250}
251
gman@chromium.orged9f9cd2013-02-27 21:12:35252void RenderbufferManager::CreateRenderbuffer(
gman@chromium.orgae51d192010-04-27 00:48:03253 GLuint client_id, GLuint service_id) {
piman@chromium.org62e65f02013-05-29 22:28:10254 scoped_refptr<Renderbuffer> renderbuffer(
255 new Renderbuffer(this, client_id, service_id));
gman@chromium.orgee2a79c32013-03-10 03:50:27256 std::pair<RenderbufferMap::iterator, bool> result =
257 renderbuffers_.insert(std::make_pair(client_id, renderbuffer));
gman@chromium.orga25fa872010-03-25 02:57:58258 DCHECK(result.second);
gman@chromium.orgee2a79c32013-03-10 03:50:27259 if (!renderbuffer->cleared()) {
gman@chromium.org0d6bfdc2011-11-02 01:32:20260 ++num_uncleared_renderbuffers_;
261 }
gman@chromium.orga25fa872010-03-25 02:57:58262}
263
gman@chromium.orged9f9cd2013-02-27 21:12:35264Renderbuffer* RenderbufferManager::GetRenderbuffer(
gman@chromium.orgae51d192010-04-27 00:48:03265 GLuint client_id) {
gman@chromium.orgee2a79c32013-03-10 03:50:27266 RenderbufferMap::iterator it = renderbuffers_.find(client_id);
tzikddef02182018-08-14 07:08:33267 return it != renderbuffers_.end() ? it->second.get() : nullptr;
gman@chromium.orga25fa872010-03-25 02:57:58268}
269
gman@chromium.orged9f9cd2013-02-27 21:12:35270void RenderbufferManager::RemoveRenderbuffer(GLuint client_id) {
gman@chromium.orgee2a79c32013-03-10 03:50:27271 RenderbufferMap::iterator it = renderbuffers_.find(client_id);
272 if (it != renderbuffers_.end()) {
rsleevi@chromium.org7cd76fd2013-06-02 21:11:11273 Renderbuffer* renderbuffer = it->second.get();
gman@chromium.orgee2a79c32013-03-10 03:50:27274 renderbuffer->MarkAsDeleted();
275 renderbuffers_.erase(it);
gman@chromium.orga25fa872010-03-25 02:57:58276 }
277}
278
avif15d60a2015-12-21 17:06:33279bool RenderbufferManager::ComputeEstimatedRenderbufferSize(
280 int width,
281 int height,
282 int samples,
283 int internal_format,
284 uint32_t* size) const {
gman@chromium.org7989c9e2013-01-23 06:39:26285 DCHECK(size);
gman@chromium.org7989c9e2013-01-23 06:39:26286 GLenum impl_format = InternalRenderbufferFormatToImplFormat(internal_format);
Zhenyao Mo6e27f1a2019-01-18 22:52:23287 uint32_t bytes_per_pixel = GLES2Util::RenderbufferBytesPerPixel(impl_format);
288 base::CheckedNumeric<uint32_t> checked_size = width;
289 checked_size *= height;
290 checked_size *= (samples == 0 ? 1 : samples);
291 checked_size *= bytes_per_pixel;
292 return checked_size.AssignIfValid(size);
gman@chromium.org7989c9e2013-01-23 06:39:26293}
294
295GLenum RenderbufferManager::InternalRenderbufferFormatToImplFormat(
skyostil@chromium.org8e102e102013-09-20 22:50:23296 GLenum impl_format) const {
Zhenyao Mo4dff3bd92024-06-28 15:21:04297 // Upgrade 16-bit depth to 24-bit if possible.
298 if (impl_format == GL_DEPTH_COMPONENT16 &&
299 feature_info_->feature_flags().oes_depth24) {
300 return GL_DEPTH_COMPONENT24;
gman@chromium.org7989c9e2013-01-23 06:39:26301 }
302 return impl_format;
303}
304
ericrka0399f4a2015-08-20 17:13:29305bool RenderbufferManager::OnMemoryDump(
306 const base::trace_event::MemoryDumpArgs& args,
307 base::trace_event::ProcessMemoryDump* pmd) {
ericrkeff776982016-11-03 21:37:31308 using base::trace_event::MemoryAllocatorDump;
309 using base::trace_event::MemoryDumpLevelOfDetail;
kylechard167a8662018-09-14 20:16:29310 const uint64_t context_group_tracing_id =
Maggie Chen40af1efa2025-06-04 18:19:57311 memory_type_tracker_->memory_tracker()
312 ? memory_type_tracker_->memory_tracker()->ContextGroupTracingId()
313 : 0;
ericrkeff776982016-11-03 21:37:31314
Ho Cheungadbf3fb2023-09-08 02:01:11315 if (args.level_of_detail == MemoryDumpLevelOfDetail::kBackground) {
ericrkb03ea3882016-11-04 23:08:42316 std::string dump_name =
kylechard167a8662018-09-14 20:16:29317 base::StringPrintf("gpu/gl/renderbuffers/context_group_0x%" PRIX64,
318 context_group_tracing_id);
ericrkeff776982016-11-03 21:37:31319 MemoryAllocatorDump* dump = pmd->CreateAllocatorDump(dump_name);
320 dump->AddScalar(MemoryAllocatorDump::kNameSize,
321 MemoryAllocatorDump::kUnitsBytes, mem_represented());
322
323 // Early out, no need for more detail in a BACKGROUND dump.
324 return true;
325 }
326
ericrka0399f4a2015-08-20 17:13:29327 for (const auto& renderbuffer_entry : renderbuffers_) {
328 const auto& client_renderbuffer_id = renderbuffer_entry.first;
329 const auto& renderbuffer = renderbuffer_entry.second;
330
erikchen3158c942017-06-19 23:43:00331 std::string dump_name =
kylechard167a8662018-09-14 20:16:29332 base::StringPrintf("gpu/gl/renderbuffers/context_group_0x%" PRIX64
erikchen3158c942017-06-19 23:43:00333 "/renderbuffer_0x%" PRIX32,
kylechard167a8662018-09-14 20:16:29334 context_group_tracing_id, client_renderbuffer_id);
ericrkeff776982016-11-03 21:37:31335 MemoryAllocatorDump* dump = pmd->CreateAllocatorDump(dump_name);
336 dump->AddScalar(MemoryAllocatorDump::kNameSize,
337 MemoryAllocatorDump::kUnitsBytes,
ericrka0399f4a2015-08-20 17:13:29338 static_cast<uint64_t>(renderbuffer->EstimatedSize()));
339
kylechard167a8662018-09-14 20:16:29340 auto guid = gl::GetGLRenderbufferGUIDForTracing(context_group_tracing_id,
ericrkb03ea3882016-11-04 23:08:42341 client_renderbuffer_id);
ericrka0399f4a2015-08-20 17:13:29342 pmd->CreateSharedGlobalAllocatorDump(guid);
343 pmd->AddOwnershipEdge(dump->guid(), guid);
344 }
ericrkeff776982016-11-03 21:37:31345
ericrka0399f4a2015-08-20 17:13:29346 return true;
347}
348
gman@chromium.orga25fa872010-03-25 02:57:58349} // namespace gles2
350} // namespace gpu