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