diff options
author | skyostil@chromium.org <skyostil@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-09-12 18:05:13 +0000 |
---|---|---|
committer | skyostil@chromium.org <skyostil@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-09-12 18:05:13 +0000 |
commit | 8f9b8ddccb1d0ab3253e1de83cf7c90e2ad7a369 (patch) | |
tree | 4a04daaa393030dffd743d036566887416009a07 /gpu | |
parent | 084b18e4fb71f5e626f266e78b73f5536ce6908e (diff) | |
download | chromium_src-8f9b8ddccb1d0ab3253e1de83cf7c90e2ad7a369.zip chromium_src-8f9b8ddccb1d0ab3253e1de83cf7c90e2ad7a369.tar.gz chromium_src-8f9b8ddccb1d0ab3253e1de83cf7c90e2ad7a369.tar.bz2 |
gpu: Record GL state to trace
This patch adds a GL state tracer for recording information about the
context state as trace event objects. This initial version only records
a screenshot of the framebuffer contents at every SwapBuffers.
Note that because the saving this information can be expensive, the new
trace events are added under the "disabled-by-default-gpu.debug"
category.
BUG=284402
Review URL: https://chromiumcodereview.appspot.com/23926013
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@222812 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'gpu')
-rw-r--r-- | gpu/command_buffer/service/gles2_cmd_decoder.cc | 21 | ||||
-rw-r--r-- | gpu/command_buffer/service/gpu_state_tracer.cc | 131 | ||||
-rw-r--r-- | gpu/command_buffer/service/gpu_state_tracer.h | 39 | ||||
-rw-r--r-- | gpu/command_buffer_service.gypi | 2 |
4 files changed, 193 insertions, 0 deletions
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc index d6a9276..747ce78 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc @@ -42,6 +42,7 @@ #include "gpu/command_buffer/service/gl_utils.h" #include "gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.h" #include "gpu/command_buffer/service/gles2_cmd_validation.h" +#include "gpu/command_buffer/service/gpu_state_tracer.h" #include "gpu/command_buffer/service/gpu_switches.h" #include "gpu/command_buffer/service/gpu_tracer.h" #include "gpu/command_buffer/service/image_manager.h" @@ -1664,6 +1665,7 @@ class GLES2DecoderImpl : public GLES2Decoder { DecoderFramebufferState framebuffer_state_; scoped_ptr<GPUTracer> gpu_tracer_; + scoped_ptr<GPUStateTracer> gpu_state_tracer_; std::queue<linked_ptr<FenceCallback> > pending_readpixel_fences_; @@ -2127,6 +2129,7 @@ bool GLES2DecoderImpl::Initialize( set_initialized(); gpu_tracer_ = GPUTracer::Create(); + gpu_state_tracer_ = GPUStateTracer::Create(&state_); if (CommandLine::ForCurrentProcess()->HasSwitch( switches::kEnableGPUDebugging)) { @@ -7011,6 +7014,15 @@ error::Error GLES2DecoderImpl::HandlePostSubBufferCHROMIUM( "glPostSubBufferCHROMIUM", "command not supported by surface"); return error::kNoError; } + bool is_tracing; + TRACE_EVENT_CATEGORY_GROUP_ENABLED(TRACE_DISABLED_BY_DEFAULT("gpu.debug"), + &is_tracing); + if (is_tracing) { + bool is_offscreen = !!offscreen_target_frame_buffer_.get(); + ScopedFrameBufferBinder binder(this, GetBackbufferServiceId()); + gpu_state_tracer_->TakeSnapshotWithCurrentFramebuffer( + is_offscreen ? offscreen_size_ : surface_->GetSize()); + } if (surface_->PostSubBuffer(c.x, c.y, c.width, c.height)) { return error::kNoError; } else { @@ -8603,6 +8615,15 @@ void GLES2DecoderImpl::DoSwapBuffers() { TRACE_EVENT2("gpu", "GLES2DecoderImpl::DoSwapBuffers", "offscreen", is_offscreen, "frame", this_frame_number); + bool is_tracing; + TRACE_EVENT_CATEGORY_GROUP_ENABLED(TRACE_DISABLED_BY_DEFAULT("gpu.debug"), + &is_tracing); + if (is_tracing) { + ScopedFrameBufferBinder binder(this, GetBackbufferServiceId()); + gpu_state_tracer_->TakeSnapshotWithCurrentFramebuffer( + is_offscreen ? offscreen_size_ : surface_->GetSize()); + } + // If offscreen then don't actually SwapBuffers to the display. Just copy // the rendered frame to another frame buffer. if (is_offscreen) { diff --git a/gpu/command_buffer/service/gpu_state_tracer.cc b/gpu/command_buffer/service/gpu_state_tracer.cc new file mode 100644 index 0000000..dea05b3 --- /dev/null +++ b/gpu/command_buffer/service/gpu_state_tracer.cc @@ -0,0 +1,131 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "gpu/command_buffer/service/gpu_state_tracer.h" + +#include "base/base64.h" +#include "base/debug/trace_event.h" +#include "context_state.h" +#include "ui/gfx/codec/png_codec.h" +#include "ui/gl/gl_bindings.h" + +namespace gpu { +namespace gles2 { +namespace { + +const int kBytesPerPixel = 4; + +class Snapshot : public base::debug::ConvertableToTraceFormat { + public: + static scoped_ptr<Snapshot> Create(const ContextState* state); + + // Save a screenshot of the currently bound framebuffer. + bool SaveScreenshot(const gfx::Size& size); + + // base::debug::ConvertableToTraceFormat implementation. + virtual void AppendAsTraceFormat(std::string* out) const OVERRIDE; + + private: + explicit Snapshot(const ContextState* state); + + const ContextState* state_; + + std::vector<unsigned char> screenshot_pixels_; + gfx::Size screenshot_size_; + + DISALLOW_COPY_AND_ASSIGN(Snapshot); +}; + +} // namespace + +Snapshot::Snapshot(const ContextState* state) : state_(state) {} + +scoped_ptr<Snapshot> Snapshot::Create(const ContextState* state) { + return scoped_ptr<Snapshot>(new Snapshot(state)); +} + +bool Snapshot::SaveScreenshot(const gfx::Size& size) { + screenshot_size_ = size; + screenshot_pixels_.resize(screenshot_size_.width() * + screenshot_size_.height() * kBytesPerPixel); + + glPixelStorei(GL_PACK_ALIGNMENT, kBytesPerPixel); + glReadPixels(0, + 0, + screenshot_size_.width(), + screenshot_size_.height(), + GL_RGBA, + GL_UNSIGNED_BYTE, + &screenshot_pixels_[0]); + glPixelStorei(GL_PACK_ALIGNMENT, state_->pack_alignment); + + // Flip the screenshot vertically. + int bytes_per_row = screenshot_size_.width() * kBytesPerPixel; + for (int y = 0; y < screenshot_size_.height() / 2; y++) { + for (int x = 0; x < bytes_per_row; x++) { + std::swap(screenshot_pixels_[y * bytes_per_row + x], + screenshot_pixels_ + [(screenshot_size_.height() - y - 1) * bytes_per_row + x]); + } + } + return true; +} + +void Snapshot::AppendAsTraceFormat(std::string* out) const { + *out += "{"; + if (screenshot_pixels_.size()) { + std::vector<unsigned char> png_data; + int bytes_per_row = screenshot_size_.width() * kBytesPerPixel; + bool png_ok = gfx::PNGCodec::Encode(&screenshot_pixels_[0], + gfx::PNGCodec::FORMAT_RGBA, + screenshot_size_, + bytes_per_row, + false, + std::vector<gfx::PNGCodec::Comment>(), + &png_data); + DCHECK(png_ok); + + base::StringPiece base64_input(reinterpret_cast<const char*>(&png_data[0]), + png_data.size()); + std::string base64_output; + Base64Encode(base64_input, &base64_output); + + *out += "\"screenshot\":\"" + base64_output + "\""; + } + *out += "}"; +} + +scoped_ptr<GPUStateTracer> GPUStateTracer::Create(const ContextState* state) { + return scoped_ptr<GPUStateTracer>(new GPUStateTracer(state)); +} + +GPUStateTracer::GPUStateTracer(const ContextState* state) : state_(state) { + TRACE_EVENT_OBJECT_CREATED_WITH_ID( + TRACE_DISABLED_BY_DEFAULT("gpu.debug"), "gpu::State", state_); +} + +GPUStateTracer::~GPUStateTracer() { + TRACE_EVENT_OBJECT_DELETED_WITH_ID( + TRACE_DISABLED_BY_DEFAULT("gpu.debug"), "gpu::State", state_); +} + +void GPUStateTracer::TakeSnapshotWithCurrentFramebuffer(const gfx::Size& size) { + TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("gpu.debug"), + "GPUStateTracer::TakeSnapshotWithCurrentFramebuffer"); + + scoped_ptr<Snapshot> snapshot(Snapshot::Create(state_)); + + // Only save a screenshot for now. + if (!snapshot->SaveScreenshot(size)) + return; + + TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID( + TRACE_DISABLED_BY_DEFAULT("gpu.debug"), + "gpu::State", + state_, + snapshot.PassAs<base::debug::ConvertableToTraceFormat>()); +} + +} // namespace gles2 +} // namespace gpu diff --git a/gpu/command_buffer/service/gpu_state_tracer.h b/gpu/command_buffer/service/gpu_state_tracer.h new file mode 100644 index 0000000..38998f3 --- /dev/null +++ b/gpu/command_buffer/service/gpu_state_tracer.h @@ -0,0 +1,39 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef GPU_COMMAND_BUFFER_SERVICE_GPU_STATE_TRACER_H_ +#define GPU_COMMAND_BUFFER_SERVICE_GPU_STATE_TRACER_H_ + +#include "base/basictypes.h" +#include "base/memory/scoped_ptr.h" + +namespace gfx { +class Size; +} + +namespace gpu { +namespace gles2 { + +struct ContextState; + +// Saves GPU state such as framebuffer contents while tracing. +class GPUStateTracer { + public: + static scoped_ptr<GPUStateTracer> Create(const ContextState* state); + ~GPUStateTracer(); + + // Take a state snapshot with a screenshot of the currently bound framebuffer. + void TakeSnapshotWithCurrentFramebuffer(const gfx::Size& size); + + private: + explicit GPUStateTracer(const ContextState* state); + + const ContextState* state_; + DISALLOW_COPY_AND_ASSIGN(GPUStateTracer); +}; + +} // namespace gles2 +} // namespace gpu + +#endif // GPU_COMMAND_BUFFER_SERVICE_GPU_STATE_TRACER_H_ diff --git a/gpu/command_buffer_service.gypi b/gpu/command_buffer_service.gypi index 9c9c3f7..729baf0 100644 --- a/gpu/command_buffer_service.gypi +++ b/gpu/command_buffer_service.gypi @@ -81,6 +81,8 @@ 'command_buffer/service/gpu_scheduler.cc', 'command_buffer/service/gpu_scheduler.h', 'command_buffer/service/gpu_scheduler_mock.h', + 'command_buffer/service/gpu_state_tracer.cc', + 'command_buffer/service/gpu_state_tracer.h', 'command_buffer/service/gpu_switches.cc', 'command_buffer/service/gpu_switches.h', 'command_buffer/service/gpu_tracer.cc', |