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