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