• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2013 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/gpu_state_tracer.h"
6 
7 #include "base/base64.h"
8 #include "base/debug/trace_event.h"
9 #include "context_state.h"
10 #include "ui/gfx/codec/png_codec.h"
11 #include "ui/gl/gl_bindings.h"
12 
13 namespace gpu {
14 namespace gles2 {
15 namespace {
16 
17 const int kBytesPerPixel = 4;
18 
19 class Snapshot : public base::debug::ConvertableToTraceFormat {
20  public:
21   static scoped_refptr<Snapshot> Create(const ContextState* state);
22 
23   // Save a screenshot of the currently bound framebuffer.
24   bool SaveScreenshot(const gfx::Size& size);
25 
26   // base::debug::ConvertableToTraceFormat implementation.
27   virtual void AppendAsTraceFormat(std::string* out) const OVERRIDE;
28 
29  private:
30   explicit Snapshot(const ContextState* state);
~Snapshot()31   virtual ~Snapshot() {}
32 
33   const ContextState* state_;
34 
35   std::vector<unsigned char> screenshot_pixels_;
36   gfx::Size screenshot_size_;
37 
38   DISALLOW_COPY_AND_ASSIGN(Snapshot);
39 };
40 
41 }  // namespace
42 
Snapshot(const ContextState * state)43 Snapshot::Snapshot(const ContextState* state) : state_(state) {}
44 
Create(const ContextState * state)45 scoped_refptr<Snapshot> Snapshot::Create(const ContextState* state) {
46   return scoped_refptr<Snapshot>(new Snapshot(state));
47 }
48 
SaveScreenshot(const gfx::Size & size)49 bool Snapshot::SaveScreenshot(const gfx::Size& size) {
50   screenshot_size_ = size;
51   screenshot_pixels_.resize(screenshot_size_.width() *
52                             screenshot_size_.height() * kBytesPerPixel);
53 
54   glPixelStorei(GL_PACK_ALIGNMENT, kBytesPerPixel);
55   glReadPixels(0,
56                0,
57                screenshot_size_.width(),
58                screenshot_size_.height(),
59                GL_RGBA,
60                GL_UNSIGNED_BYTE,
61                &screenshot_pixels_[0]);
62   glPixelStorei(GL_PACK_ALIGNMENT, state_->pack_alignment);
63 
64   // Flip the screenshot vertically.
65   int bytes_per_row = screenshot_size_.width() * kBytesPerPixel;
66   for (int y = 0; y < screenshot_size_.height() / 2; y++) {
67     for (int x = 0; x < bytes_per_row; x++) {
68       std::swap(screenshot_pixels_[y * bytes_per_row + x],
69                 screenshot_pixels_
70                     [(screenshot_size_.height() - y - 1) * bytes_per_row + x]);
71     }
72   }
73   return true;
74 }
75 
AppendAsTraceFormat(std::string * out) const76 void Snapshot::AppendAsTraceFormat(std::string* out) const {
77   *out += "{";
78   if (screenshot_pixels_.size()) {
79     std::vector<unsigned char> png_data;
80     int bytes_per_row = screenshot_size_.width() * kBytesPerPixel;
81     bool png_ok = gfx::PNGCodec::Encode(&screenshot_pixels_[0],
82                                         gfx::PNGCodec::FORMAT_RGBA,
83                                         screenshot_size_,
84                                         bytes_per_row,
85                                         false,
86                                         std::vector<gfx::PNGCodec::Comment>(),
87                                         &png_data);
88     DCHECK(png_ok);
89 
90     base::StringPiece base64_input(reinterpret_cast<const char*>(&png_data[0]),
91                                    png_data.size());
92     std::string base64_output;
93     Base64Encode(base64_input, &base64_output);
94 
95     *out += "\"screenshot\":\"" + base64_output + "\"";
96   }
97   *out += "}";
98 }
99 
Create(const ContextState * state)100 scoped_ptr<GPUStateTracer> GPUStateTracer::Create(const ContextState* state) {
101   return scoped_ptr<GPUStateTracer>(new GPUStateTracer(state));
102 }
103 
GPUStateTracer(const ContextState * state)104 GPUStateTracer::GPUStateTracer(const ContextState* state) : state_(state) {
105   TRACE_EVENT_OBJECT_CREATED_WITH_ID(
106       TRACE_DISABLED_BY_DEFAULT("gpu.debug"), "gpu::State", state_);
107 }
108 
~GPUStateTracer()109 GPUStateTracer::~GPUStateTracer() {
110   TRACE_EVENT_OBJECT_DELETED_WITH_ID(
111       TRACE_DISABLED_BY_DEFAULT("gpu.debug"), "gpu::State", state_);
112 }
113 
TakeSnapshotWithCurrentFramebuffer(const gfx::Size & size)114 void GPUStateTracer::TakeSnapshotWithCurrentFramebuffer(const gfx::Size& size) {
115   TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("gpu.debug"),
116                "GPUStateTracer::TakeSnapshotWithCurrentFramebuffer");
117 
118   scoped_refptr<Snapshot> snapshot(Snapshot::Create(state_));
119 
120   // Only save a screenshot for now.
121   if (!snapshot->SaveScreenshot(size))
122     return;
123 
124   TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(
125       TRACE_DISABLED_BY_DEFAULT("gpu.debug"),
126       "gpu::State",
127       state_,
128       scoped_refptr<base::debug::ConvertableToTraceFormat>(snapshot));
129 }
130 
131 }  // namespace gles2
132 }  // namespace gpu
133