summaryrefslogtreecommitdiffstats
path: root/gpu
diff options
context:
space:
mode:
authorskyostil@chromium.org <skyostil@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-09-12 18:05:13 +0000
committerskyostil@chromium.org <skyostil@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-09-12 18:05:13 +0000
commit8f9b8ddccb1d0ab3253e1de83cf7c90e2ad7a369 (patch)
tree4a04daaa393030dffd743d036566887416009a07 /gpu
parent084b18e4fb71f5e626f266e78b73f5536ce6908e (diff)
downloadchromium_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.cc21
-rw-r--r--gpu/command_buffer/service/gpu_state_tracer.cc131
-rw-r--r--gpu/command_buffer/service/gpu_state_tracer.h39
-rw-r--r--gpu/command_buffer_service.gypi2
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',