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.
5 #include "gpu/command_buffer/service/gpu_state_tracer.h"
7 #include "base/base64.h"
8 #include "base/trace_event/trace_event.h"
9 #include "context_state.h"
10 #include "ui/gfx/codec/png_codec.h"
11 #include "ui/gl/gl_bindings.h"
17 const int kBytesPerPixel
= 4;
19 class Snapshot
: public base::trace_event::ConvertableToTraceFormat
{
21 static scoped_refptr
<Snapshot
> Create(const ContextState
* state
);
23 // Save a screenshot of the currently bound framebuffer.
24 bool SaveScreenshot(const gfx::Size
& size
);
26 // base::trace_event::ConvertableToTraceFormat implementation.
27 void AppendAsTraceFormat(std::string
* out
) const override
;
30 explicit Snapshot(const ContextState
* state
);
31 ~Snapshot() override
{}
33 const ContextState
* state_
;
35 std::vector
<unsigned char> screenshot_pixels_
;
36 gfx::Size screenshot_size_
;
38 DISALLOW_COPY_AND_ASSIGN(Snapshot
);
43 Snapshot::Snapshot(const ContextState
* state
) : state_(state
) {}
45 scoped_refptr
<Snapshot
> Snapshot::Create(const ContextState
* state
) {
46 return scoped_refptr
<Snapshot
>(new Snapshot(state
));
49 bool Snapshot::SaveScreenshot(const gfx::Size
& size
) {
50 screenshot_size_
= size
;
51 screenshot_pixels_
.resize(screenshot_size_
.width() *
52 screenshot_size_
.height() * kBytesPerPixel
);
54 glPixelStorei(GL_PACK_ALIGNMENT
, kBytesPerPixel
);
57 screenshot_size_
.width(),
58 screenshot_size_
.height(),
61 &screenshot_pixels_
[0]);
62 glPixelStorei(GL_PACK_ALIGNMENT
, state_
->pack_alignment
);
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
],
70 [(screenshot_size_
.height() - y
- 1) * bytes_per_row
+ x
]);
76 void Snapshot::AppendAsTraceFormat(std::string
* out
) const {
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
,
86 std::vector
<gfx::PNGCodec::Comment
>(),
90 base::StringPiece
base64_input(reinterpret_cast<const char*>(&png_data
[0]),
92 std::string base64_output
;
93 Base64Encode(base64_input
, &base64_output
);
95 *out
+= "\"screenshot\":\"" + base64_output
+ "\"";
100 scoped_ptr
<GPUStateTracer
> GPUStateTracer::Create(const ContextState
* state
) {
101 return scoped_ptr
<GPUStateTracer
>(new GPUStateTracer(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_
);
109 GPUStateTracer::~GPUStateTracer() {
110 TRACE_EVENT_OBJECT_DELETED_WITH_ID(
111 TRACE_DISABLED_BY_DEFAULT("gpu.debug"), "gpu::State", state_
);
114 void GPUStateTracer::TakeSnapshotWithCurrentFramebuffer(const gfx::Size
& size
) {
115 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("gpu.debug"),
116 "GPUStateTracer::TakeSnapshotWithCurrentFramebuffer");
118 scoped_refptr
<Snapshot
> snapshot(Snapshot::Create(state_
));
120 // Only save a screenshot for now.
121 if (!snapshot
->SaveScreenshot(size
))
124 TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(
125 TRACE_DISABLED_BY_DEFAULT("gpu.debug"),
128 scoped_refptr
<base::trace_event::ConvertableToTraceFormat
>(snapshot
));