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 13namespace gpu { 14namespace gles2 { 15namespace { 16 17const int kBytesPerPixel = 4; 18 19class 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 43Snapshot::Snapshot(const ContextState* state) : state_(state) {} 44 45scoped_refptr<Snapshot> Snapshot::Create(const ContextState* state) { 46 return scoped_refptr<Snapshot>(new Snapshot(state)); 47} 48 49bool 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 76void 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 100scoped_ptr<GPUStateTracer> GPUStateTracer::Create(const ContextState* state) { 101 return scoped_ptr<GPUStateTracer>(new GPUStateTracer(state)); 102} 103 104GPUStateTracer::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 109GPUStateTracer::~GPUStateTracer() { 110 TRACE_EVENT_OBJECT_DELETED_WITH_ID( 111 TRACE_DISABLED_BY_DEFAULT("gpu.debug"), "gpu::State", state_); 112} 113 114void 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