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