Home | History | Annotate | Download | only in service
      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);
     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 
     43 Snapshot::Snapshot(const ContextState* state) : state_(state) {}
     44 
     45 scoped_refptr<Snapshot> Snapshot::Create(const ContextState* state) {
     46   return scoped_refptr<Snapshot>(new Snapshot(state));
     47 }
     48 
     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 
     76 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 
    100 scoped_ptr<GPUStateTracer> GPUStateTracer::Create(const ContextState* state) {
    101   return scoped_ptr<GPUStateTracer>(new GPUStateTracer(state));
    102 }
    103 
    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 
    109 GPUStateTracer::~GPUStateTracer() {
    110   TRACE_EVENT_OBJECT_DELETED_WITH_ID(
    111       TRACE_DISABLED_BY_DEFAULT("gpu.debug"), "gpu::State", state_);
    112 }
    113 
    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