<commit_before>#ifndef EBITEN_GRAPHICS_DETAIL_OPENGL_GRAPHICS_CONTEXT_HPP
#define EBITEN_GRAPHICS_DETAIL_OPENGL_GRAPHICS_CONTEXT_HPP

#include "ebiten/graphics/detail/opengl/opengl.hpp"
#include "ebiten/graphics/detail/opengl/texture_factory.hpp"
#include "ebiten/graphics/detail/opengl/shaders.hpp"
#include "ebiten/graphics/color_matrix.hpp"
#include "ebiten/graphics/geometry_matrix.hpp"
#include "ebiten/graphics/texture.hpp"
#include "ebiten/noncopyable.hpp"
#include <array>
#include <algorithm>
#include <cassert>
#include <unordered_map>

namespace ebiten {
namespace graphics {
namespace detail {

class device;

class graphics_context : private noncopyable {
  friend class device;
private:
  std::size_t screen_width_;
  std::size_t screen_height_;
  std::size_t const screen_scale_;
  texture_factory& texture_factory_;
  shaders shaders_;
  GLuint current_program_;
  std::array<float, 16> projection_matrix_;
  texture empty_texture_;
  std::unordered_map<texture_id, GLuint> framebuffers_;
  bool is_initialized_;
  GLuint main_framebuffer_;
private:
  graphics_context(std::size_t const screen_width,
                   std::size_t const screen_height,
                   std::size_t const screen_scale,
                   texture_factory& texture_factory)
    : screen_width_(screen_width),
      screen_height_(screen_height),
      screen_scale_(screen_scale),
      texture_factory_(texture_factory),
      current_program_(0),
      is_initialized_(false),
      main_framebuffer_(0) {
  }
public:
  void
  initialize() {
    if (this->is_initialized_) {
      return;
    }
    GLint main_framebuffer = 0;
    // The main framebuffer should be created sooner than any other framebuffers!
    // TODO: Refactoring
    ::glGetIntegerv(GL_FRAMEBUFFER_BINDING, &main_framebuffer);
    this->main_framebuffer_ = main_framebuffer;
    this->is_initialized_ = true;
  }
  void
  clear() {
    ::glClearColor(0, 0, 0, 1);
    ::glClear(GL_COLOR_BUFFER_BIT);
  }
  void
  fill(uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha) {
    ::glClearColor(red   / 255.0,
                   green / 255.0,
                   blue  / 255.0,
                   alpha / 255.0);
    ::glClear(GL_COLOR_BUFFER_BIT);
  }
  // Only for debugging?
  void
  draw_rect(std::size_t x, std::size_t y, std::size_t width, std::size_t height,
            uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha) {
    if (!this->empty_texture_) {
      this->empty_texture_ = this->texture_factory_.create(16, 16);
    }
    assert(static_cast<bool>(this->empty_texture_));

    geometry_matrix geom_mat;
    geom_mat.set_a(static_cast<double>(width)  / this->empty_texture_.width());
    geom_mat.set_d(static_cast<double>(height) / this->empty_texture_.height());
    geom_mat.set_tx(x);
    geom_mat.set_ty(y);

    color_matrix color_mat;
    color_mat.set_element(0, 4, red   / 255.0);
    color_mat.set_element(1, 4, green / 255.0);
    color_mat.set_element(2, 4, blue  / 255.0);
    color_mat.set_element(3, 4, alpha / 255.0);

    this->draw_texture(this->empty_texture_,
                       0, 0, this->empty_texture_.width(), this->empty_texture_.height(),
                       geom_mat, color_mat);
  }
  // TODO: double -> int
  void
  draw_texture(texture const& texture,
               double src_x, double src_y, double src_width, double src_height,
               geometry_matrix const& geometry_matrix,
               color_matrix const& color_matrix) {
    this->set_shader_program(geometry_matrix, color_matrix);
    // TODO: cache? Check other callings of glBindTexture.
    ::glBindTexture(GL_TEXTURE_2D, texture.id());
    // TODO: replace float to short?
    // http://objective-audio.jp/2009/07/ngmoco-opengl.html
    // 選べるようにするといいかも
    float const texture_width  = texture.texture_width();
    float const texture_height = texture.texture_height();
    float const tu1 = src_x                / texture_width;
    float const tu2 = (src_x + src_width)  / texture_width;
    float const tv1 = src_y                / texture_height;
    float const tv2 = (src_y + src_height) / texture_height;
    float const x1 = 0;
    float const x2 = src_width;
    float const y1 = 0;
    float const y2 = src_height;
    float const vertex[] = {x1, y1,
                            x2, y1,
                            x1, y2,
                            x2, y2,};
    float const tex_coord[] = {tu1, tv1,
                               tu2, tv1,
                               tu1, tv2,
                               tu2, tv2,};

    GLint const vertex_attr_location = ::glGetAttribLocation(this->current_program_,
                                                             "vertex");
    assert(vertex_attr_location != -1);
    GLint const texture_attr_location = ::glGetAttribLocation(this->current_program_,
                                                              "texture");
    assert(texture_attr_location != -1);

    // TODO: use glMultiDrawArrays?
    ::glEnableClientState(GL_VERTEX_ARRAY);
    ::glEnableClientState(GL_TEXTURE_COORD_ARRAY);
    ::glEnableVertexAttribArray(vertex_attr_location);
    ::glEnableVertexAttribArray(texture_attr_location);
    ::glVertexAttribPointer(vertex_attr_location, 2, GL_FLOAT, GL_FALSE,
                            0, vertex);
    ::glVertexAttribPointer(texture_attr_location, 2, GL_FLOAT, GL_FALSE,
                            0, tex_coord);
    ::glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
    ::glDisableVertexAttribArray(texture_attr_location);
    ::glDisableVertexAttribArray(vertex_attr_location);
    ::glDisableClientState(GL_TEXTURE_COORD_ARRAY);
    ::glDisableClientState(GL_VERTEX_ARRAY);
  }
  void
  set_offscreen(class texture& texture) {
    this->set_offscreen(&texture);
  }
private:
  void
  set_screen_size(std::size_t screen_width,
                  std::size_t screen_height) {
    assert(0 < screen_width);
    assert(0 < screen_height);
    assert(screen_width  <= 4096);
    assert(screen_height <= 4096);
    this->screen_width_  = screen_width;
    this->screen_height_ = screen_height;
  }
  // TODO: I don't wanna use pointers!
  void
  set_offscreen(class texture* texture) {
    // TODO: cache
    GLuint framebuffer;
    if (texture) {
      framebuffer = this->get_framebuffer(*texture);
      assert(framebuffer != 0);
    } else {
      framebuffer = this->main_framebuffer_;
    }
    ::glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
    assert(::glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
    ::glEnable(GL_BLEND);
    ::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    float width, height, tx, ty;
    if (framebuffer != this->main_framebuffer_) {
      width  = texture->texture_width();
      height = texture->texture_height();
      tx     = -1;
      ty     = -1;
    } else {
      width  = this->screen_width_ * this->screen_scale_;
      height = -1.0 * this->screen_height_ * this->screen_scale_;
      tx     = -1;
      ty     = 1;
    }
    ::glViewport(0, 0,
                 static_cast<GLsizei>(std::abs(width)),
                 static_cast<GLsizei>(std::abs(height)));
    float const projection_matrix[] = {
      2.0f / width, 0,             0, 0,
      0,            2.0f / height, 0, 0,
      0,            0,             1, 0,
      tx,           ty,            0, 1,
    };
    std::copy(std::begin(projection_matrix),
              std::end(projection_matrix),
              this->projection_matrix_.data());
  }
  void
  reset_offscreen() {
    this->set_offscreen(nullptr);
  }
  void
  flush() {
    ::glFlush();
  }
  void
  set_shader_program(geometry_matrix const& geometry_matrix,
                     color_matrix const& color_matrix) {
    GLuint program;
    if (color_matrix.is_identity()) {
      program = this->shaders_.regular_shader_program();
    } else {
      program = this->shaders_.color_mat_shader_program();
    }
    // TODO: cache and skip?
    ::glUseProgram(program);
    this->current_program_ = program;
    {
      GLint location = ::glGetUniformLocation(program, "projection_matrix");
      assert(location != -1);
      ::glUniformMatrix4fv(location,
                           1, GL_FALSE, this->projection_matrix_.data());
    }
    {
      graphics::geometry_matrix const& mat = geometry_matrix;
      float a  = static_cast<float>(mat.a());
      float b  = static_cast<float>(mat.b());
      float c  = static_cast<float>(mat.c());
      float d  = static_cast<float>(mat.d());
      float tx = static_cast<float>(mat.tx());
      float ty = static_cast<float>(mat.ty());
      float const gl_modelview_mat[] = {a,  c,  0, 0,
                                        b,  d,  0, 0,
                                        0,  0,  1, 0,
                                        tx, ty, 0, 1};
      {
        GLint location = ::glGetUniformLocation(program, "modelview_matrix");
        assert(location != -1);
        ::glUniformMatrix4fv(location,
                             1, GL_FALSE, gl_modelview_mat);
      }
    }
    {
      GLint location = ::glGetUniformLocation(program, "texture");
      assert(location != -1);
      ::glUniform1i(location, 0);
    }
    if (program == this->shaders_.color_mat_shader_program()) {
      graphics::color_matrix const& mat = color_matrix;
#define e(i, j) static_cast<float>(mat.element(i, j))
      float const gl_color_mat[] = {
        e(0, 0), e(0, 1), e(0, 2), e(0, 3),
        e(1, 0), e(1, 1), e(1, 2), e(1, 3),
        e(2, 0), e(2, 1), e(2, 2), e(2, 3),
        e(3, 0), e(3, 1), e(3, 2), e(3, 3),
      };
      float const gl_color_mat_translation[] = {
        e(0, 4), e(1, 4), e(2, 4), e(3, 4),
      };
#undef e
      {
        GLint location = glGetUniformLocation(program, "color_matrix");
        assert(location != -1);
        ::glUniformMatrix4fv(location, 1, GL_FALSE, gl_color_mat);
      }
      {
        GLint location = glGetUniformLocation(program, "color_matrix_translation");
        assert(location != -1);
        ::glUniform4fv(location, 1, gl_color_mat_translation);
      }
    }
  }
  GLuint
  get_framebuffer(texture const& texture) {
    auto const& it = this->framebuffers_.find(texture.id());
    if (it != this->framebuffers_.end()) {
      return it->second;
    }
    GLuint framebuffer;
    ::glGenFramebuffers(1, &framebuffer);
    {
      GLint orig_framebuffer;
      ::glGetIntegerv(GL_FRAMEBUFFER_BINDING, &orig_framebuffer);
      ::glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
      ::glFramebufferTexture2D(GL_FRAMEBUFFER,
                               GL_COLOR_ATTACHMENT0,
                               GL_TEXTURE_2D,
                               texture.id(),
                               0);
      ::glBindFramebuffer(GL_FRAMEBUFFER, orig_framebuffer);
    }
    if (::glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
      throw std::runtime_error("framebuffer is not supported completely");
    }
    return this->framebuffers_[texture.id()] = framebuffer;
  }
  void
  delete_framebuffer(texture const& texture) {
    auto const& it = this->framebuffers_.find(texture.id());
    if (it == this->framebuffers_.end()) {
      return;
    }
    ::glDeleteFramebuffers(1, &it->second);
    this->framebuffers_.erase(texture.id());
  }
};

}
}
}

#endif
<commit_msg>Removed the pointer in graphics_context#set_offscreen<commit_after>#ifndef EBITEN_GRAPHICS_DETAIL_OPENGL_GRAPHICS_CONTEXT_HPP
#define EBITEN_GRAPHICS_DETAIL_OPENGL_GRAPHICS_CONTEXT_HPP

#include "ebiten/graphics/detail/opengl/opengl.hpp"
#include "ebiten/graphics/detail/opengl/texture_factory.hpp"
#include "ebiten/graphics/detail/opengl/shaders.hpp"
#include "ebiten/graphics/color_matrix.hpp"
#include "ebiten/graphics/geometry_matrix.hpp"
#include "ebiten/graphics/texture.hpp"
#include "ebiten/noncopyable.hpp"
#include <array>
#include <algorithm>
#include <cassert>
#include <unordered_map>

namespace ebiten {
namespace graphics {
namespace detail {

class device;

class graphics_context : private noncopyable {
  friend class device;
private:
  std::size_t screen_width_;
  std::size_t screen_height_;
  std::size_t const screen_scale_;
  texture_factory& texture_factory_;
  shaders shaders_;
  GLuint current_program_;
  std::array<float, 16> projection_matrix_;
  texture empty_texture_;
  std::unordered_map<texture_id, GLuint> framebuffers_;
  bool is_initialized_;
  GLuint main_framebuffer_;
private:
  graphics_context(std::size_t const screen_width,
                   std::size_t const screen_height,
                   std::size_t const screen_scale,
                   texture_factory& texture_factory)
    : screen_width_(screen_width),
      screen_height_(screen_height),
      screen_scale_(screen_scale),
      texture_factory_(texture_factory),
      current_program_(0),
      is_initialized_(false),
      main_framebuffer_(0) {
  }
public:
  void
  initialize() {
    if (this->is_initialized_) {
      return;
    }
    GLint main_framebuffer = 0;
    // The main framebuffer should be created sooner than any other framebuffers!
    // TODO: Refactoring
    ::glGetIntegerv(GL_FRAMEBUFFER_BINDING, &main_framebuffer);
    this->main_framebuffer_ = main_framebuffer;
    this->is_initialized_ = true;
  }
  void
  clear() {
    ::glClearColor(0, 0, 0, 1);
    ::glClear(GL_COLOR_BUFFER_BIT);
  }
  void
  fill(uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha) {
    ::glClearColor(red   / 255.0,
                   green / 255.0,
                   blue  / 255.0,
                   alpha / 255.0);
    ::glClear(GL_COLOR_BUFFER_BIT);
  }
  // Only for debugging?
  void
  draw_rect(std::size_t x, std::size_t y, std::size_t width, std::size_t height,
            uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha) {
    if (!this->empty_texture_) {
      this->empty_texture_ = this->texture_factory_.create(16, 16);
    }
    assert(static_cast<bool>(this->empty_texture_));

    geometry_matrix geom_mat;
    geom_mat.set_a(static_cast<double>(width)  / this->empty_texture_.width());
    geom_mat.set_d(static_cast<double>(height) / this->empty_texture_.height());
    geom_mat.set_tx(x);
    geom_mat.set_ty(y);

    color_matrix color_mat;
    color_mat.set_element(0, 4, red   / 255.0);
    color_mat.set_element(1, 4, green / 255.0);
    color_mat.set_element(2, 4, blue  / 255.0);
    color_mat.set_element(3, 4, alpha / 255.0);

    this->draw_texture(this->empty_texture_,
                       0, 0, this->empty_texture_.width(), this->empty_texture_.height(),
                       geom_mat, color_mat);
  }
  // TODO: double -> int
  void
  draw_texture(texture const& texture,
               double src_x, double src_y, double src_width, double src_height,
               geometry_matrix const& geometry_matrix,
               color_matrix const& color_matrix) {
    this->set_shader_program(geometry_matrix, color_matrix);
    // TODO: cache? Check other callings of glBindTexture.
    ::glBindTexture(GL_TEXTURE_2D, texture.id());
    // TODO: replace float to short?
    // http://objective-audio.jp/2009/07/ngmoco-opengl.html
    // 選べるようにするといいかも
    float const texture_width  = texture.texture_width();
    float const texture_height = texture.texture_height();
    float const tu1 = src_x                / texture_width;
    float const tu2 = (src_x + src_width)  / texture_width;
    float const tv1 = src_y                / texture_height;
    float const tv2 = (src_y + src_height) / texture_height;
    float const x1 = 0;
    float const x2 = src_width;
    float const y1 = 0;
    float const y2 = src_height;
    float const vertex[] = {x1, y1,
                            x2, y1,
                            x1, y2,
                            x2, y2,};
    float const tex_coord[] = {tu1, tv1,
                               tu2, tv1,
                               tu1, tv2,
                               tu2, tv2,};

    GLint const vertex_attr_location = ::glGetAttribLocation(this->current_program_,
                                                             "vertex");
    assert(vertex_attr_location != -1);
    GLint const texture_attr_location = ::glGetAttribLocation(this->current_program_,
                                                              "texture");
    assert(texture_attr_location != -1);

    // TODO: use glMultiDrawArrays?
    ::glEnableClientState(GL_VERTEX_ARRAY);
    ::glEnableClientState(GL_TEXTURE_COORD_ARRAY);
    ::glEnableVertexAttribArray(vertex_attr_location);
    ::glEnableVertexAttribArray(texture_attr_location);
    ::glVertexAttribPointer(vertex_attr_location, 2, GL_FLOAT, GL_FALSE,
                            0, vertex);
    ::glVertexAttribPointer(texture_attr_location, 2, GL_FLOAT, GL_FALSE,
                            0, tex_coord);
    ::glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
    ::glDisableVertexAttribArray(texture_attr_location);
    ::glDisableVertexAttribArray(vertex_attr_location);
    ::glDisableClientState(GL_TEXTURE_COORD_ARRAY);
    ::glDisableClientState(GL_VERTEX_ARRAY);
  }
  void
  set_offscreen(class texture& texture) {
    // TODO: cache
    GLuint framebuffer;
    if (texture) {
      framebuffer = this->get_framebuffer(texture);
      assert(framebuffer != 0);
    } else {
      framebuffer = this->main_framebuffer_;
    }
    ::glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
    assert(::glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
    ::glEnable(GL_BLEND);
    ::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    float width, height, tx, ty;
    if (framebuffer != this->main_framebuffer_) {
      width  = texture.texture_width();
      height = texture.texture_height();
      tx     = -1;
      ty     = -1;
    } else {
      width  = this->screen_width_ * this->screen_scale_;
      height = -1.0 * this->screen_height_ * this->screen_scale_;
      tx     = -1;
      ty     = 1;
    }
    ::glViewport(0, 0,
                 static_cast<GLsizei>(std::abs(width)),
                 static_cast<GLsizei>(std::abs(height)));
    float const projection_matrix[] = {
      2.0f / width, 0,             0, 0,
      0,            2.0f / height, 0, 0,
      0,            0,             1, 0,
      tx,           ty,            0, 1,
    };
    std::copy(std::begin(projection_matrix),
              std::end(projection_matrix),
              this->projection_matrix_.data());
  }
private:
  void
  set_screen_size(std::size_t screen_width,
                  std::size_t screen_height) {
    assert(0 < screen_width);
    assert(0 < screen_height);
    assert(screen_width  <= 4096);
    assert(screen_height <= 4096);
    this->screen_width_  = screen_width;
    this->screen_height_ = screen_height;
  }
  void
  reset_offscreen() {
    texture t;
    this->set_offscreen(t);
  }
  void
  flush() {
    ::glFlush();
  }
  void
  set_shader_program(geometry_matrix const& geometry_matrix,
                     color_matrix const& color_matrix) {
    GLuint program;
    if (color_matrix.is_identity()) {
      program = this->shaders_.regular_shader_program();
    } else {
      program = this->shaders_.color_mat_shader_program();
    }
    // TODO: cache and skip?
    ::glUseProgram(program);
    this->current_program_ = program;
    {
      GLint location = ::glGetUniformLocation(program, "projection_matrix");
      assert(location != -1);
      ::glUniformMatrix4fv(location,
                           1, GL_FALSE, this->projection_matrix_.data());
    }
    {
      graphics::geometry_matrix const& mat = geometry_matrix;
      float a  = static_cast<float>(mat.a());
      float b  = static_cast<float>(mat.b());
      float c  = static_cast<float>(mat.c());
      float d  = static_cast<float>(mat.d());
      float tx = static_cast<float>(mat.tx());
      float ty = static_cast<float>(mat.ty());
      float const gl_modelview_mat[] = {a,  c,  0, 0,
                                        b,  d,  0, 0,
                                        0,  0,  1, 0,
                                        tx, ty, 0, 1};
      {
        GLint location = ::glGetUniformLocation(program, "modelview_matrix");
        assert(location != -1);
        ::glUniformMatrix4fv(location,
                             1, GL_FALSE, gl_modelview_mat);
      }
    }
    {
      GLint location = ::glGetUniformLocation(program, "texture");
      assert(location != -1);
      ::glUniform1i(location, 0);
    }
    if (program == this->shaders_.color_mat_shader_program()) {
      graphics::color_matrix const& mat = color_matrix;
#define e(i, j) static_cast<float>(mat.element(i, j))
      float const gl_color_mat[] = {
        e(0, 0), e(0, 1), e(0, 2), e(0, 3),
        e(1, 0), e(1, 1), e(1, 2), e(1, 3),
        e(2, 0), e(2, 1), e(2, 2), e(2, 3),
        e(3, 0), e(3, 1), e(3, 2), e(3, 3),
      };
      float const gl_color_mat_translation[] = {
        e(0, 4), e(1, 4), e(2, 4), e(3, 4),
      };
#undef e
      {
        GLint location = glGetUniformLocation(program, "color_matrix");
        assert(location != -1);
        ::glUniformMatrix4fv(location, 1, GL_FALSE, gl_color_mat);
      }
      {
        GLint location = glGetUniformLocation(program, "color_matrix_translation");
        assert(location != -1);
        ::glUniform4fv(location, 1, gl_color_mat_translation);
      }
    }
  }
  GLuint
  get_framebuffer(texture const& texture) {
    auto const& it = this->framebuffers_.find(texture.id());
    if (it != this->framebuffers_.end()) {
      return it->second;
    }
    GLuint framebuffer;
    ::glGenFramebuffers(1, &framebuffer);
    {
      GLint orig_framebuffer;
      ::glGetIntegerv(GL_FRAMEBUFFER_BINDING, &orig_framebuffer);
      ::glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
      ::glFramebufferTexture2D(GL_FRAMEBUFFER,
                               GL_COLOR_ATTACHMENT0,
                               GL_TEXTURE_2D,
                               texture.id(),
                               0);
      ::glBindFramebuffer(GL_FRAMEBUFFER, orig_framebuffer);
    }
    if (::glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
      throw std::runtime_error("framebuffer is not supported completely");
    }
    return this->framebuffers_[texture.id()] = framebuffer;
  }
  void
  delete_framebuffer(texture const& texture) {
    auto const& it = this->framebuffers_.find(texture.id());
    if (it == this->framebuffers_.end()) {
      return;
    }
    ::glDeleteFramebuffers(1, &it->second);
    this->framebuffers_.erase(texture.id());
  }
};

}
}
}

#endif
<|endoftext|>


<commit_before>/*
 * Copyright 2014 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "GrGLProgramBuilder.h"

#include "GrAutoLocaleSetter.h"
#include "GrContext.h"
#include "GrCoordTransform.h"
#include "GrGLProgramBuilder.h"
#include "GrProgramDesc.h"
#include "GrShaderCaps.h"
#include "GrSwizzle.h"
#include "SkAutoMalloc.h"
#include "SkATrace.h"
#include "SkTraceEvent.h"
#include "gl/GrGLGpu.h"
#include "gl/GrGLProgram.h"
#include "gl/builders/GrGLShaderStringBuilder.h"
#include "glsl/GrGLSLFragmentProcessor.h"
#include "glsl/GrGLSLGeometryProcessor.h"
#include "glsl/GrGLSLProgramDataManager.h"
#include "glsl/GrGLSLXferProcessor.h"

#define GL_CALL(X) GR_GL_CALL(this->gpu()->glInterface(), X)
#define GL_CALL_RET(R, X) GR_GL_CALL_RET(this->gpu()->glInterface(), R, X)

GrGLProgram* GrGLProgramBuilder::CreateProgram(const GrPipeline& pipeline,
                                               const GrPrimitiveProcessor& primProc,
                                               GrProgramDesc* desc,
                                               GrGLGpu* gpu) {
    SkASSERT(!pipeline.isBad() && primProc.instantiate(gpu->getContext()->resourceProvider()));

    ATRACE_ANDROID_FRAMEWORK("Shader Compile");
    GrAutoLocaleSetter als("C");

    // create a builder.  This will be handed off to effects so they can use it to add
    // uniforms, varyings, textures, etc
    GrGLProgramBuilder builder(gpu, pipeline, primProc, desc);

    if (gpu->getContext()->getPersistentCache() && gpu->glCaps().programBinarySupport()) {
        sk_sp<SkData> key = SkData::MakeWithoutCopy(desc->asKey(), desc->keyLength());
        builder.fCached = gpu->getContext()->getPersistentCache()->load(*key);
        // the eventual end goal is to completely skip emitAndInstallProcs on a cache hit, but it's
        // doing necessary setup in addition to generating the SkSL code. Currently we are only able
        // to skip the SkSL->GLSL step on a cache hit.
    }
    if (!builder.emitAndInstallProcs()) {
        builder.cleanupFragmentProcessors();
        return nullptr;
    }
    return builder.finalize();
}

/////////////////////////////////////////////////////////////////////////////

GrGLProgramBuilder::GrGLProgramBuilder(GrGLGpu* gpu,
                                       const GrPipeline& pipeline,
                                       const GrPrimitiveProcessor& primProc,
                                       GrProgramDesc* desc)
    : INHERITED(pipeline, primProc, desc)
    , fGpu(gpu)
    , fVaryingHandler(this)
    , fUniformHandler(this) {
}

const GrCaps* GrGLProgramBuilder::caps() const {
    return fGpu->caps();
}

bool GrGLProgramBuilder::compileAndAttachShaders(const char* glsl,
                                                 int length,
                                                 GrGLuint programId,
                                                 GrGLenum type,
                                                 SkTDArray<GrGLuint>* shaderIds,
                                                 const SkSL::Program::Settings& settings,
                                                 const SkSL::Program::Inputs& inputs) {
    GrGLGpu* gpu = this->gpu();
    GrGLuint shaderId = GrGLCompileAndAttachShader(gpu->glContext(),
                                                   programId,
                                                   type,
                                                   glsl,
                                                   length,
                                                   gpu->stats(),
                                                   settings);
    if (!shaderId) {
        return false;
    }

    *shaderIds->append() = shaderId;
    if (inputs.fFlipY) {
        GrProgramDesc* d = this->desc();
        d->setSurfaceOriginKey(GrGLSLFragmentShaderBuilder::KeyForSurfaceOrigin(
                                                     this->pipeline().proxy()->origin()));
        d->finalize();
    }

    return true;
}

bool GrGLProgramBuilder::compileAndAttachShaders(GrGLSLShaderBuilder& shader,
                                                 GrGLuint programId,
                                                 GrGLenum type,
                                                 SkTDArray<GrGLuint>* shaderIds,
                                                 const SkSL::Program::Settings& settings,
                                                 SkSL::Program::Inputs* outInputs) {
    SkSL::String glsl;
    std::unique_ptr<SkSL::Program> program = GrSkSLtoGLSL(gpu()->glContext(), type,
                                                 shader.fCompilerStrings.begin(),
                                                 shader.fCompilerStringLengths.begin(),
                                                 shader.fCompilerStrings.count(),
                                                 settings,
                                                 &glsl);
    *outInputs = program->fInputs;
    return this->compileAndAttachShaders(glsl.c_str(),
                                         glsl.size(),
                                         programId,
                                         type,
                                         shaderIds,
                                         settings,
                                         *outInputs);
}

GrGLProgram* GrGLProgramBuilder::finalize() {
    TRACE_EVENT0("skia", TRACE_FUNC);

    // verify we can get a program id
    GrGLuint programID;
    GL_CALL_RET(programID, CreateProgram());
    if (0 == programID) {
        this->cleanupFragmentProcessors();
        return nullptr;
    }

    if (this->gpu()->glCaps().programBinarySupport() &&
        this->gpu()->getContext()->getPersistentCache()) {
        GL_CALL(ProgramParameteri(programID, GR_GL_PROGRAM_BINARY_RETRIEVABLE_HINT, GR_GL_TRUE));
    }

    this->finalizeShaders();

    // compile shaders and bind attributes / uniforms
    const GrPrimitiveProcessor& primProc = this->primitiveProcessor();
    SkSL::Program::Settings settings;
    settings.fCaps = this->gpu()->glCaps().shaderCaps();
    settings.fFlipY = this->pipeline().proxy()->origin() != kTopLeft_GrSurfaceOrigin;
    SkSL::Program::Inputs inputs;
    SkTDArray<GrGLuint> shadersToDelete;
    bool cached = nullptr != fCached.get();
    if (cached) {
        // cache hit, just hand the binary to GL
        const uint8_t* bytes = fCached->bytes();
        size_t offset = 0;
        memcpy(&inputs, bytes + offset, sizeof(inputs));
        offset += sizeof(inputs);
        int binaryFormat;
        memcpy(&binaryFormat, bytes + offset, sizeof(binaryFormat));
        offset += sizeof(binaryFormat);
        GL_CALL(ProgramBinary(programID, binaryFormat, (void*) (bytes + offset),
                              fCached->size() - offset));
    } else {
        // cache miss, compile shaders
        if (fFS.fForceHighPrecision) {
            settings.fForceHighPrecision = true;
        }
        SkSL::String glsl;
        std::unique_ptr<SkSL::Program> fs = GrSkSLtoGLSL(gpu()->glContext(),
                                                         GR_GL_FRAGMENT_SHADER,
                                                         fFS.fCompilerStrings.begin(),
                                                         fFS.fCompilerStringLengths.begin(),
                                                         fFS.fCompilerStrings.count(),
                                                         settings,
                                                         &glsl);
        inputs = fs->fInputs;
        if (inputs.fRTHeight) {
            this->addRTHeightUniform(SKSL_RTHEIGHT_NAME);
        }
        if (!this->compileAndAttachShaders(glsl.c_str(), glsl.size(), programID,
                                           GR_GL_FRAGMENT_SHADER, &shadersToDelete, settings,
                                           inputs)) {
            this->cleanupProgram(programID, shadersToDelete);
            return nullptr;
        }

        std::unique_ptr<SkSL::Program> vs = GrSkSLtoGLSL(gpu()->glContext(),
                                                         GR_GL_VERTEX_SHADER,
                                                         fVS.fCompilerStrings.begin(),
                                                         fVS.fCompilerStringLengths.begin(),
                                                         fVS.fCompilerStrings.count(),
                                                         settings,
                                                         &glsl);
        if (!this->compileAndAttachShaders(glsl.c_str(), glsl.size(), programID,
                                           GR_GL_VERTEX_SHADER, &shadersToDelete, settings,
                                           inputs)) {
            this->cleanupProgram(programID, shadersToDelete);
            return nullptr;
        }

        // NVPR actually requires a vertex shader to compile
        bool useNvpr = primProc.isPathRendering();
        if (!useNvpr) {
            int vaCount = primProc.numAttribs();
            for (int i = 0; i < vaCount; i++) {
                GL_CALL(BindAttribLocation(programID, i, primProc.getAttrib(i).fName));
            }
        }

        if (primProc.willUseGeoShader()) {
            std::unique_ptr<SkSL::Program> gs;
            gs = GrSkSLtoGLSL(gpu()->glContext(),
                              GR_GL_GEOMETRY_SHADER,
                              fGS.fCompilerStrings.begin(),
                              fGS.fCompilerStringLengths.begin(),
                              fGS.fCompilerStrings.count(),
                              settings,
                              &glsl);
            if (!this->compileAndAttachShaders(glsl.c_str(), glsl.size(), programID,
                                               GR_GL_GEOMETRY_SHADER, &shadersToDelete, settings,
                                               inputs)) {
                this->cleanupProgram(programID, shadersToDelete);
                return nullptr;
            }

        }
        this->bindProgramResourceLocations(programID);

        GL_CALL(LinkProgram(programID));
    }
    // Calling GetProgramiv is expensive in Chromium. Assume success in release builds.
    bool checkLinked = kChromium_GrGLDriver != fGpu->ctxInfo().driver();
#ifdef SK_DEBUG
    checkLinked = true;
#endif
    if (checkLinked) {
        if (!this->checkLinkStatus(programID)) {
            SkDebugf("VS:\n");
            GrGLPrintShader(fGpu->glContext(), GR_GL_VERTEX_SHADER, fVS.fCompilerStrings.begin(),
                            fVS.fCompilerStringLengths.begin(), fVS.fCompilerStrings.count(),
                            settings);
            if (primProc.willUseGeoShader()) {
                SkDebugf("\nGS:\n");
                GrGLPrintShader(fGpu->glContext(), GR_GL_GEOMETRY_SHADER,
                                fGS.fCompilerStrings.begin(), fGS.fCompilerStringLengths.begin(),
                                fGS.fCompilerStrings.count(), settings);
            }
            SkDebugf("\nFS:\n");
            GrGLPrintShader(fGpu->glContext(), GR_GL_FRAGMENT_SHADER, fFS.fCompilerStrings.begin(),
                            fFS.fCompilerStringLengths.begin(), fFS.fCompilerStrings.count(),
                            settings);
            SkDEBUGFAIL("");
            return nullptr;
        }
    }
    this->resolveProgramResourceLocations(programID);

    this->cleanupShaders(shadersToDelete);
    if (!cached && this->gpu()->getContext()->getPersistentCache() &&
        fGpu->glCaps().programBinarySupport()) {
        // store shader in cache
        sk_sp<SkData> key = SkData::MakeWithoutCopy(desc()->asKey(), desc()->keyLength());
        GrGLsizei length = 0;
        GrGLenum binaryFormat;
        GL_CALL(GetProgramiv(programID, GL_PROGRAM_BINARY_LENGTH, &length));
        std::unique_ptr<char> binary(new char[length]);
        GL_CALL(GetProgramBinary(programID, length, &length, &binaryFormat, binary.get()));
        size_t dataLength = sizeof(inputs) + sizeof(binaryFormat) + length;
        std::unique_ptr<uint8_t> data((uint8_t*) malloc(dataLength));
        size_t offset = 0;
        memcpy(data.get() + offset, &inputs, sizeof(inputs));
        offset += sizeof(inputs);
        memcpy(data.get() + offset, &binaryFormat, sizeof(binaryFormat));
        offset += sizeof(binaryFormat);
        memcpy(data.get() + offset, binary.get(), length);
        this->gpu()->getContext()->getPersistentCache()->store(*key,
                                                               *SkData::MakeWithoutCopy(data.get(),
                                                                                dataLength));
    }
    return this->createProgram(programID);
}

void GrGLProgramBuilder::bindProgramResourceLocations(GrGLuint programID) {
    fUniformHandler.bindUniformLocations(programID, fGpu->glCaps());

    const GrGLCaps& caps = this->gpu()->glCaps();
    if (fFS.hasCustomColorOutput() && caps.bindFragDataLocationSupport()) {
        GL_CALL(BindFragDataLocation(programID, 0,
                                     GrGLSLFragmentShaderBuilder::DeclaredColorOutputName()));
    }
    if (fFS.hasSecondaryOutput() && caps.shaderCaps()->mustDeclareFragmentShaderOutput()) {
        GL_CALL(BindFragDataLocationIndexed(programID, 0, 1,
                                  GrGLSLFragmentShaderBuilder::DeclaredSecondaryColorOutputName()));
    }

    // handle NVPR separable varyings
    if (!fGpu->glCaps().shaderCaps()->pathRenderingSupport() ||
        !fGpu->glPathRendering()->shouldBindFragmentInputs()) {
        return;
    }
    int count = fVaryingHandler.fPathProcVaryingInfos.count();
    for (int i = 0; i < count; ++i) {
        GL_CALL(BindFragmentInputLocation(programID, i,
                                       fVaryingHandler.fPathProcVaryingInfos[i].fVariable.c_str()));
        fVaryingHandler.fPathProcVaryingInfos[i].fLocation = i;
    }
}

bool GrGLProgramBuilder::checkLinkStatus(GrGLuint programID) {
    GrGLint linked = GR_GL_INIT_ZERO;
    GL_CALL(GetProgramiv(programID, GR_GL_LINK_STATUS, &linked));
    if (!linked) {
        SkDebugf("Program linking failed.\n");
        GrGLint infoLen = GR_GL_INIT_ZERO;
        GL_CALL(GetProgramiv(programID, GR_GL_INFO_LOG_LENGTH, &infoLen));
        SkAutoMalloc log(sizeof(char)*(infoLen+1));  // outside if for debugger
        if (infoLen > 0) {
            // retrieve length even though we don't need it to workaround
            // bug in chrome cmd buffer param validation.
            GrGLsizei length = GR_GL_INIT_ZERO;
            GL_CALL(GetProgramInfoLog(programID,
                                      infoLen+1,
                                      &length,
                                      (char*)log.get()));
            SkDebugf("%s", (char*)log.get());
        }
        GL_CALL(DeleteProgram(programID));
        programID = 0;
    }
    return SkToBool(linked);
}

void GrGLProgramBuilder::resolveProgramResourceLocations(GrGLuint programID) {
    fUniformHandler.getUniformLocations(programID, fGpu->glCaps());

    // handle NVPR separable varyings
    if (!fGpu->glCaps().shaderCaps()->pathRenderingSupport() ||
        fGpu->glPathRendering()->shouldBindFragmentInputs()) {
        return;
    }
    int count = fVaryingHandler.fPathProcVaryingInfos.count();
    for (int i = 0; i < count; ++i) {
        GrGLint location;
        GL_CALL_RET(location, GetProgramResourceLocation(
                                       programID,
                                       GR_GL_FRAGMENT_INPUT,
                                       fVaryingHandler.fPathProcVaryingInfos[i].fVariable.c_str()));
        fVaryingHandler.fPathProcVaryingInfos[i].fLocation = location;
    }
}

void GrGLProgramBuilder::cleanupProgram(GrGLuint programID, const SkTDArray<GrGLuint>& shaderIDs) {
    GL_CALL(DeleteProgram(programID));
    this->cleanupShaders(shaderIDs);
    this->cleanupFragmentProcessors();
}
void GrGLProgramBuilder::cleanupShaders(const SkTDArray<GrGLuint>& shaderIDs) {
    for (int i = 0; i < shaderIDs.count(); ++i) {
      GL_CALL(DeleteShader(shaderIDs[i]));
    }
}

GrGLProgram* GrGLProgramBuilder::createProgram(GrGLuint programID) {
    return new GrGLProgram(fGpu,
                           *this->desc(),
                           fUniformHandles,
                           programID,
                           fUniformHandler.fUniforms,
                           fUniformHandler.fSamplers,
                           fUniformHandler.fTexelBuffers,
                           fVaryingHandler.fPathProcVaryingInfos,
                           std::move(fGeometryProcessor),
                           std::move(fXferProcessor),
                           fFragmentProcessors);
}
<commit_msg>Fix shader initialization on a cache hit<commit_after>/*
 * Copyright 2014 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "GrGLProgramBuilder.h"

#include "GrAutoLocaleSetter.h"
#include "GrContext.h"
#include "GrCoordTransform.h"
#include "GrGLProgramBuilder.h"
#include "GrProgramDesc.h"
#include "GrShaderCaps.h"
#include "GrSwizzle.h"
#include "SkAutoMalloc.h"
#include "SkATrace.h"
#include "SkTraceEvent.h"
#include "gl/GrGLGpu.h"
#include "gl/GrGLProgram.h"
#include "gl/builders/GrGLShaderStringBuilder.h"
#include "glsl/GrGLSLFragmentProcessor.h"
#include "glsl/GrGLSLGeometryProcessor.h"
#include "glsl/GrGLSLProgramDataManager.h"
#include "glsl/GrGLSLXferProcessor.h"

#define GL_CALL(X) GR_GL_CALL(this->gpu()->glInterface(), X)
#define GL_CALL_RET(R, X) GR_GL_CALL_RET(this->gpu()->glInterface(), R, X)

GrGLProgram* GrGLProgramBuilder::CreateProgram(const GrPipeline& pipeline,
                                               const GrPrimitiveProcessor& primProc,
                                               GrProgramDesc* desc,
                                               GrGLGpu* gpu) {
    SkASSERT(!pipeline.isBad() && primProc.instantiate(gpu->getContext()->resourceProvider()));

    ATRACE_ANDROID_FRAMEWORK("Shader Compile");
    GrAutoLocaleSetter als("C");

    // create a builder.  This will be handed off to effects so they can use it to add
    // uniforms, varyings, textures, etc
    GrGLProgramBuilder builder(gpu, pipeline, primProc, desc);

    if (gpu->getContext()->getPersistentCache() && gpu->glCaps().programBinarySupport()) {
        sk_sp<SkData> key = SkData::MakeWithoutCopy(desc->asKey(), desc->keyLength());
        builder.fCached = gpu->getContext()->getPersistentCache()->load(*key);
        // the eventual end goal is to completely skip emitAndInstallProcs on a cache hit, but it's
        // doing necessary setup in addition to generating the SkSL code. Currently we are only able
        // to skip the SkSL->GLSL step on a cache hit.
    }
    if (!builder.emitAndInstallProcs()) {
        builder.cleanupFragmentProcessors();
        return nullptr;
    }
    return builder.finalize();
}

/////////////////////////////////////////////////////////////////////////////

GrGLProgramBuilder::GrGLProgramBuilder(GrGLGpu* gpu,
                                       const GrPipeline& pipeline,
                                       const GrPrimitiveProcessor& primProc,
                                       GrProgramDesc* desc)
    : INHERITED(pipeline, primProc, desc)
    , fGpu(gpu)
    , fVaryingHandler(this)
    , fUniformHandler(this) {
}

const GrCaps* GrGLProgramBuilder::caps() const {
    return fGpu->caps();
}

bool GrGLProgramBuilder::compileAndAttachShaders(const char* glsl,
                                                 int length,
                                                 GrGLuint programId,
                                                 GrGLenum type,
                                                 SkTDArray<GrGLuint>* shaderIds,
                                                 const SkSL::Program::Settings& settings,
                                                 const SkSL::Program::Inputs& inputs) {
    GrGLGpu* gpu = this->gpu();
    GrGLuint shaderId = GrGLCompileAndAttachShader(gpu->glContext(),
                                                   programId,
                                                   type,
                                                   glsl,
                                                   length,
                                                   gpu->stats(),
                                                   settings);
    if (!shaderId) {
        return false;
    }

    *shaderIds->append() = shaderId;
    if (inputs.fFlipY) {
        GrProgramDesc* d = this->desc();
        d->setSurfaceOriginKey(GrGLSLFragmentShaderBuilder::KeyForSurfaceOrigin(
                                                     this->pipeline().proxy()->origin()));
        d->finalize();
    }

    return true;
}

bool GrGLProgramBuilder::compileAndAttachShaders(GrGLSLShaderBuilder& shader,
                                                 GrGLuint programId,
                                                 GrGLenum type,
                                                 SkTDArray<GrGLuint>* shaderIds,
                                                 const SkSL::Program::Settings& settings,
                                                 SkSL::Program::Inputs* outInputs) {
    SkSL::String glsl;
    std::unique_ptr<SkSL::Program> program = GrSkSLtoGLSL(gpu()->glContext(), type,
                                                 shader.fCompilerStrings.begin(),
                                                 shader.fCompilerStringLengths.begin(),
                                                 shader.fCompilerStrings.count(),
                                                 settings,
                                                 &glsl);
    *outInputs = program->fInputs;
    return this->compileAndAttachShaders(glsl.c_str(),
                                         glsl.size(),
                                         programId,
                                         type,
                                         shaderIds,
                                         settings,
                                         *outInputs);
}

GrGLProgram* GrGLProgramBuilder::finalize() {
    TRACE_EVENT0("skia", TRACE_FUNC);

    // verify we can get a program id
    GrGLuint programID;
    GL_CALL_RET(programID, CreateProgram());
    if (0 == programID) {
        this->cleanupFragmentProcessors();
        return nullptr;
    }

    if (this->gpu()->glCaps().programBinarySupport() &&
        this->gpu()->getContext()->getPersistentCache()) {
        GL_CALL(ProgramParameteri(programID, GR_GL_PROGRAM_BINARY_RETRIEVABLE_HINT, GR_GL_TRUE));
    }

    this->finalizeShaders();

    // compile shaders and bind attributes / uniforms
    const GrPrimitiveProcessor& primProc = this->primitiveProcessor();
    SkSL::Program::Settings settings;
    settings.fCaps = this->gpu()->glCaps().shaderCaps();
    settings.fFlipY = this->pipeline().proxy()->origin() != kTopLeft_GrSurfaceOrigin;
    SkSL::Program::Inputs inputs;
    SkTDArray<GrGLuint> shadersToDelete;
    bool cached = nullptr != fCached.get();
    if (cached) {
        this->bindProgramResourceLocations(programID);
        // cache hit, just hand the binary to GL
        const uint8_t* bytes = fCached->bytes();
        size_t offset = 0;
        memcpy(&inputs, bytes + offset, sizeof(inputs));
        offset += sizeof(inputs);
        if (inputs.fRTHeight) {
            this->addRTHeightUniform(SKSL_RTHEIGHT_NAME);
        }
        int binaryFormat;
        memcpy(&binaryFormat, bytes + offset, sizeof(binaryFormat));
        offset += sizeof(binaryFormat);
        GL_CALL(ProgramBinary(programID, binaryFormat, (void*) (bytes + offset),
                              fCached->size() - offset));
    } else {
        // cache miss, compile shaders
        if (fFS.fForceHighPrecision) {
            settings.fForceHighPrecision = true;
        }
        SkSL::String glsl;
        std::unique_ptr<SkSL::Program> fs = GrSkSLtoGLSL(gpu()->glContext(),
                                                         GR_GL_FRAGMENT_SHADER,
                                                         fFS.fCompilerStrings.begin(),
                                                         fFS.fCompilerStringLengths.begin(),
                                                         fFS.fCompilerStrings.count(),
                                                         settings,
                                                         &glsl);
        inputs = fs->fInputs;
        if (inputs.fRTHeight) {
            this->addRTHeightUniform(SKSL_RTHEIGHT_NAME);
        }
        if (!this->compileAndAttachShaders(glsl.c_str(), glsl.size(), programID,
                                           GR_GL_FRAGMENT_SHADER, &shadersToDelete, settings,
                                           inputs)) {
            this->cleanupProgram(programID, shadersToDelete);
            return nullptr;
        }

        std::unique_ptr<SkSL::Program> vs = GrSkSLtoGLSL(gpu()->glContext(),
                                                         GR_GL_VERTEX_SHADER,
                                                         fVS.fCompilerStrings.begin(),
                                                         fVS.fCompilerStringLengths.begin(),
                                                         fVS.fCompilerStrings.count(),
                                                         settings,
                                                         &glsl);
        if (!this->compileAndAttachShaders(glsl.c_str(), glsl.size(), programID,
                                           GR_GL_VERTEX_SHADER, &shadersToDelete, settings,
                                           inputs)) {
            this->cleanupProgram(programID, shadersToDelete);
            return nullptr;
        }

        // NVPR actually requires a vertex shader to compile
        bool useNvpr = primProc.isPathRendering();
        if (!useNvpr) {
            int vaCount = primProc.numAttribs();
            for (int i = 0; i < vaCount; i++) {
                GL_CALL(BindAttribLocation(programID, i, primProc.getAttrib(i).fName));
            }
        }

        if (primProc.willUseGeoShader()) {
            std::unique_ptr<SkSL::Program> gs;
            gs = GrSkSLtoGLSL(gpu()->glContext(),
                              GR_GL_GEOMETRY_SHADER,
                              fGS.fCompilerStrings.begin(),
                              fGS.fCompilerStringLengths.begin(),
                              fGS.fCompilerStrings.count(),
                              settings,
                              &glsl);
            if (!this->compileAndAttachShaders(glsl.c_str(), glsl.size(), programID,
                                               GR_GL_GEOMETRY_SHADER, &shadersToDelete, settings,
                                               inputs)) {
                this->cleanupProgram(programID, shadersToDelete);
                return nullptr;
            }

        }
        this->bindProgramResourceLocations(programID);

        GL_CALL(LinkProgram(programID));
    }
    // Calling GetProgramiv is expensive in Chromium. Assume success in release builds.
    bool checkLinked = kChromium_GrGLDriver != fGpu->ctxInfo().driver();
#ifdef SK_DEBUG
    checkLinked = true;
#endif
    if (checkLinked) {
        if (!this->checkLinkStatus(programID)) {
            SkDebugf("VS:\n");
            GrGLPrintShader(fGpu->glContext(), GR_GL_VERTEX_SHADER, fVS.fCompilerStrings.begin(),
                            fVS.fCompilerStringLengths.begin(), fVS.fCompilerStrings.count(),
                            settings);
            if (primProc.willUseGeoShader()) {
                SkDebugf("\nGS:\n");
                GrGLPrintShader(fGpu->glContext(), GR_GL_GEOMETRY_SHADER,
                                fGS.fCompilerStrings.begin(), fGS.fCompilerStringLengths.begin(),
                                fGS.fCompilerStrings.count(), settings);
            }
            SkDebugf("\nFS:\n");
            GrGLPrintShader(fGpu->glContext(), GR_GL_FRAGMENT_SHADER, fFS.fCompilerStrings.begin(),
                            fFS.fCompilerStringLengths.begin(), fFS.fCompilerStrings.count(),
                            settings);
            SkDEBUGFAIL("");
            return nullptr;
        }
    }
    this->resolveProgramResourceLocations(programID);

    this->cleanupShaders(shadersToDelete);
    if (!cached && this->gpu()->getContext()->getPersistentCache() &&
        fGpu->glCaps().programBinarySupport()) {
        // store shader in cache
        sk_sp<SkData> key = SkData::MakeWithoutCopy(desc()->asKey(), desc()->keyLength());
        GrGLsizei length = 0;
        GrGLenum binaryFormat;
        GL_CALL(GetProgramiv(programID, GL_PROGRAM_BINARY_LENGTH, &length));
        std::unique_ptr<char> binary(new char[length]);
        GL_CALL(GetProgramBinary(programID, length, &length, &binaryFormat, binary.get()));
        size_t dataLength = sizeof(inputs) + sizeof(binaryFormat) + length;
        std::unique_ptr<uint8_t> data((uint8_t*) malloc(dataLength));
        size_t offset = 0;
        memcpy(data.get() + offset, &inputs, sizeof(inputs));
        offset += sizeof(inputs);
        memcpy(data.get() + offset, &binaryFormat, sizeof(binaryFormat));
        offset += sizeof(binaryFormat);
        memcpy(data.get() + offset, binary.get(), length);
        this->gpu()->getContext()->getPersistentCache()->store(*key,
                                                               *SkData::MakeWithoutCopy(data.get(),
                                                                                dataLength));
    }
    return this->createProgram(programID);
}

void GrGLProgramBuilder::bindProgramResourceLocations(GrGLuint programID) {
    fUniformHandler.bindUniformLocations(programID, fGpu->glCaps());

    const GrGLCaps& caps = this->gpu()->glCaps();
    if (fFS.hasCustomColorOutput() && caps.bindFragDataLocationSupport()) {
        GL_CALL(BindFragDataLocation(programID, 0,
                                     GrGLSLFragmentShaderBuilder::DeclaredColorOutputName()));
    }
    if (fFS.hasSecondaryOutput() && caps.shaderCaps()->mustDeclareFragmentShaderOutput()) {
        GL_CALL(BindFragDataLocationIndexed(programID, 0, 1,
                                  GrGLSLFragmentShaderBuilder::DeclaredSecondaryColorOutputName()));
    }

    // handle NVPR separable varyings
    if (!fGpu->glCaps().shaderCaps()->pathRenderingSupport() ||
        !fGpu->glPathRendering()->shouldBindFragmentInputs()) {
        return;
    }
    int count = fVaryingHandler.fPathProcVaryingInfos.count();
    for (int i = 0; i < count; ++i) {
        GL_CALL(BindFragmentInputLocation(programID, i,
                                       fVaryingHandler.fPathProcVaryingInfos[i].fVariable.c_str()));
        fVaryingHandler.fPathProcVaryingInfos[i].fLocation = i;
    }
}

bool GrGLProgramBuilder::checkLinkStatus(GrGLuint programID) {
    GrGLint linked = GR_GL_INIT_ZERO;
    GL_CALL(GetProgramiv(programID, GR_GL_LINK_STATUS, &linked));
    if (!linked) {
        SkDebugf("Program linking failed.\n");
        GrGLint infoLen = GR_GL_INIT_ZERO;
        GL_CALL(GetProgramiv(programID, GR_GL_INFO_LOG_LENGTH, &infoLen));
        SkAutoMalloc log(sizeof(char)*(infoLen+1));  // outside if for debugger
        if (infoLen > 0) {
            // retrieve length even though we don't need it to workaround
            // bug in chrome cmd buffer param validation.
            GrGLsizei length = GR_GL_INIT_ZERO;
            GL_CALL(GetProgramInfoLog(programID,
                                      infoLen+1,
                                      &length,
                                      (char*)log.get()));
            SkDebugf("%s", (char*)log.get());
        }
        GL_CALL(DeleteProgram(programID));
        programID = 0;
    }
    return SkToBool(linked);
}

void GrGLProgramBuilder::resolveProgramResourceLocations(GrGLuint programID) {
    fUniformHandler.getUniformLocations(programID, fGpu->glCaps());

    // handle NVPR separable varyings
    if (!fGpu->glCaps().shaderCaps()->pathRenderingSupport() ||
        fGpu->glPathRendering()->shouldBindFragmentInputs()) {
        return;
    }
    int count = fVaryingHandler.fPathProcVaryingInfos.count();
    for (int i = 0; i < count; ++i) {
        GrGLint location;
        GL_CALL_RET(location, GetProgramResourceLocation(
                                       programID,
                                       GR_GL_FRAGMENT_INPUT,
                                       fVaryingHandler.fPathProcVaryingInfos[i].fVariable.c_str()));
        fVaryingHandler.fPathProcVaryingInfos[i].fLocation = location;
    }
}

void GrGLProgramBuilder::cleanupProgram(GrGLuint programID, const SkTDArray<GrGLuint>& shaderIDs) {
    GL_CALL(DeleteProgram(programID));
    this->cleanupShaders(shaderIDs);
    this->cleanupFragmentProcessors();
}
void GrGLProgramBuilder::cleanupShaders(const SkTDArray<GrGLuint>& shaderIDs) {
    for (int i = 0; i < shaderIDs.count(); ++i) {
      GL_CALL(DeleteShader(shaderIDs[i]));
    }
}

GrGLProgram* GrGLProgramBuilder::createProgram(GrGLuint programID) {
    return new GrGLProgram(fGpu,
                           *this->desc(),
                           fUniformHandles,
                           programID,
                           fUniformHandler.fUniforms,
                           fUniformHandler.fSamplers,
                           fUniformHandler.fTexelBuffers,
                           fVaryingHandler.fPathProcVaryingInfos,
                           std::move(fGeometryProcessor),
                           std::move(fXferProcessor),
                           fFragmentProcessors);
}
<|endoftext|>


<commit_before>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/download/download_status_updater.h"

#include <string>
#include <shobjidl.h>

#include "base/file_path.h"
#include "base/logging.h"
#include "base/stl_util.h"
#include "base/string_number_conversions.h"
#include "base/win/metro.h"
#include "base/win/scoped_comptr.h"
#include "base/win/windows_version.h"
#include "chrome/browser/platform_util.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_list.h"
#include "chrome/browser/ui/browser_window.h"
#include "content/public/browser/browser_thread.h"
#include "googleurl/src/gurl.h"
#include "grit/generated_resources.h"
#include "ui/base/l10n/l10n_util.h"

// This code doesn't compile with Aura on. TODO(avi): hook it up so that
// win_aura can do platform integration.
#if !defined(USE_AURA)

namespace {

const char kDownloadNotificationPrefix[] = "DownloadNotification";
int g_next_notification_id = 0;

void UpdateTaskbarProgressBar(int download_count,
                              bool progress_known,
                              float progress) {
  // Taskbar progress bar is only supported on Win7.
  if (base::win::GetVersion() < base::win::VERSION_WIN7)
    return;

  base::win::ScopedComPtr<ITaskbarList3> taskbar;
  HRESULT result = taskbar.CreateInstance(CLSID_TaskbarList, NULL,
                                          CLSCTX_INPROC_SERVER);
  if (FAILED(result)) {
    VLOG(1) << "Failed creating a TaskbarList object: " << result;
    return;
  }

  result = taskbar->HrInit();
  if (FAILED(result)) {
    LOG(ERROR) << "Failed initializing an ITaskbarList3 interface.";
    return;
  }

  // Iterate through all the browser windows, and draw the progress bar.
  for (BrowserList::const_iterator browser_iterator = BrowserList::begin();
      browser_iterator != BrowserList::end(); browser_iterator++) {
    Browser* browser = *browser_iterator;
    BrowserWindow* window = browser->window();
    if (!window)
      continue;
    HWND frame = window->GetNativeWindow();
    if (download_count == 0 || progress == 1.0f)
      taskbar->SetProgressState(frame, TBPF_NOPROGRESS);
    else if (!progress_known)
      taskbar->SetProgressState(frame, TBPF_INDETERMINATE);
    else
      taskbar->SetProgressValue(frame, static_cast<int>(progress * 100), 100);
  }
}

void MetroDownloadNotificationClickedHandler(const wchar_t* download_path) {
  // Metro chrome will invoke these handlers on the metro thread.
  DCHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));

  // Ensure that we invoke the function to display the downloaded item on the
  // UI thread.
  content::BrowserThread::PostTask(
      content::BrowserThread::UI, FROM_HERE,
      base::Bind(platform_util::ShowItemInFolder, FilePath(download_path)));
}

}  // namespace

void DownloadStatusUpdater::UpdateAppIconDownloadProgress(
    content::DownloadItem* download) {

  // Always update overall progress.
  float progress = 0;
  int download_count = 0;
  bool progress_known = GetProgress(&progress, &download_count);
  UpdateTaskbarProgressBar(download_count, progress_known, progress);

  // Fire notifications when downloads complete.
  if (!base::win::IsMetroProcess())
    return;

  if (download->GetState() != content::DownloadItem::COMPLETE)
    return;

  if (download->GetOpenWhenComplete() ||
      download->ShouldOpenFileBasedOnExtension() ||
      download->IsTemporary() ||
      download->GetAutoOpened())
    return;

  // In Windows 8 metro mode display a metro style notification which
  // informs the user that the download is complete.
  HMODULE metro = base::win::GetMetroModule();
  base::win::MetroNotification display_notification =
      reinterpret_cast<base::win::MetroNotification>(
          ::GetProcAddress(metro, "DisplayNotification"));
  DCHECK(display_notification);
  if (display_notification) {
    string16 title = l10n_util::GetStringUTF16(
        IDS_METRO_DOWNLOAD_COMPLETE_NOTIFICATION_TITLE);
    string16 body = l10n_util::GetStringUTF16(
        IDS_METRO_DOWNLOAD_COMPLETE_NOTIFICATION);

    // Dummy notification id. Every metro style notification needs a
    // unique notification id.
    std::string notification_id = kDownloadNotificationPrefix;
    notification_id += base::IntToString(g_next_notification_id++);

    display_notification(download->GetURL().spec().c_str(),
                         "",
                         title.c_str(),
                         body.c_str(),
                         L"",
                         notification_id.c_str(),
                         MetroDownloadNotificationClickedHandler,
                         download->GetTargetFilePath().value().c_str());
  }
}

#endif  // !USE_AURA
<commit_msg>Chrome in Windows 8 metro mode should display download complete notifications only for non incognito profiles and if we are not in the foreground.<commit_after>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/download/download_status_updater.h"

#include <string>
#include <shobjidl.h>

#include "base/file_path.h"
#include "base/logging.h"
#include "base/stl_util.h"
#include "base/string_number_conversions.h"
#include "base/win/metro.h"
#include "base/win/scoped_comptr.h"
#include "base/win/windows_version.h"
#include "chrome/browser/platform_util.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_list.h"
#include "chrome/browser/ui/browser_window.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_thread.h"
#include "googleurl/src/gurl.h"
#include "grit/generated_resources.h"
#include "ui/base/l10n/l10n_util.h"

// This code doesn't compile with Aura on. TODO(avi): hook it up so that
// win_aura can do platform integration.
#if !defined(USE_AURA)

namespace {

const char kDownloadNotificationPrefix[] = "DownloadNotification";
int g_next_notification_id = 0;

void UpdateTaskbarProgressBar(int download_count,
                              bool progress_known,
                              float progress) {
  // Taskbar progress bar is only supported on Win7.
  if (base::win::GetVersion() < base::win::VERSION_WIN7)
    return;

  base::win::ScopedComPtr<ITaskbarList3> taskbar;
  HRESULT result = taskbar.CreateInstance(CLSID_TaskbarList, NULL,
                                          CLSCTX_INPROC_SERVER);
  if (FAILED(result)) {
    VLOG(1) << "Failed creating a TaskbarList object: " << result;
    return;
  }

  result = taskbar->HrInit();
  if (FAILED(result)) {
    LOG(ERROR) << "Failed initializing an ITaskbarList3 interface.";
    return;
  }

  // Iterate through all the browser windows, and draw the progress bar.
  for (BrowserList::const_iterator browser_iterator = BrowserList::begin();
      browser_iterator != BrowserList::end(); browser_iterator++) {
    Browser* browser = *browser_iterator;
    BrowserWindow* window = browser->window();
    if (!window)
      continue;
    HWND frame = window->GetNativeWindow();
    if (download_count == 0 || progress == 1.0f)
      taskbar->SetProgressState(frame, TBPF_NOPROGRESS);
    else if (!progress_known)
      taskbar->SetProgressState(frame, TBPF_INDETERMINATE);
    else
      taskbar->SetProgressValue(frame, static_cast<int>(progress * 100), 100);
  }
}

void MetroDownloadNotificationClickedHandler(const wchar_t* download_path) {
  // Metro chrome will invoke these handlers on the metro thread.
  DCHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));

  // Ensure that we invoke the function to display the downloaded item on the
  // UI thread.
  content::BrowserThread::PostTask(
      content::BrowserThread::UI, FROM_HERE,
      base::Bind(platform_util::ShowItemInFolder, FilePath(download_path)));
}

}  // namespace

void DownloadStatusUpdater::UpdateAppIconDownloadProgress(
    content::DownloadItem* download) {

  // Always update overall progress.
  float progress = 0;
  int download_count = 0;
  bool progress_known = GetProgress(&progress, &download_count);
  UpdateTaskbarProgressBar(download_count, progress_known, progress);

  // Fire notifications when downloads complete.
  if (!base::win::IsMetroProcess())
    return;

  if (download->GetState() != content::DownloadItem::COMPLETE)
    return;

  if (download->GetOpenWhenComplete() ||
      download->ShouldOpenFileBasedOnExtension() ||
      download->IsTemporary() ||
      download->GetAutoOpened())
    return;

  // Don't display the Windows8 metro notifications for an incognito download.
  if (download->GetBrowserContext() &&
      download->GetBrowserContext()->IsOffTheRecord())
    return;

  // Don't display the Windows 8 metro notifications if we are in the
  // foreground.
  HWND foreground_window = ::GetForegroundWindow();
  if (::IsWindow(foreground_window)) {
    DWORD process_id = 0;
    ::GetWindowThreadProcessId(foreground_window, &process_id);
    if (process_id == ::GetCurrentProcessId())
      return;
  }

  // In Windows 8 metro mode display a metro style notification which
  // informs the user that the download is complete.
  HMODULE metro = base::win::GetMetroModule();
  base::win::MetroNotification display_notification =
      reinterpret_cast<base::win::MetroNotification>(
          ::GetProcAddress(metro, "DisplayNotification"));
  DCHECK(display_notification);
  if (display_notification) {
    string16 title = l10n_util::GetStringUTF16(
        IDS_METRO_DOWNLOAD_COMPLETE_NOTIFICATION_TITLE);
    string16 body = l10n_util::GetStringUTF16(
        IDS_METRO_DOWNLOAD_COMPLETE_NOTIFICATION);

    // Dummy notification id. Every metro style notification needs a
    // unique notification id.
    std::string notification_id = kDownloadNotificationPrefix;
    notification_id += base::IntToString(g_next_notification_id++);

    display_notification(download->GetURL().spec().c_str(),
                         "",
                         title.c_str(),
                         body.c_str(),
                         L"",
                         notification_id.c_str(),
                         MetroDownloadNotificationClickedHandler,
                         download->GetTargetFilePath().value().c_str());
  }
}

#endif  // !USE_AURA
<|endoftext|>


<commit_before><commit_msg>Marking ExtensionApiTest.Storage flaky only on Linux.<commit_after><|endoftext|>


<commit_before>/*************************************************
* SHA-160 Source File                            *
* (C) 1999-2008 The Botan Project                *
*************************************************/

#include <botan/sha160.h>
#include <botan/loadstor.h>
#include <botan/bit_ops.h>

namespace Botan {

namespace {

/*************************************************
* SHA-160 F1 Function                            *
*************************************************/
inline void F1(u32bit A, u32bit& B, u32bit C, u32bit D, u32bit& E, u32bit msg)
   {
   E += (D ^ (B & (C ^ D))) + msg + 0x5A827999 + rotate_left(A, 5);
   B  = rotate_left(B, 30);
   }

/*************************************************
* SHA-160 F2 Function                            *
*************************************************/
inline void F2(u32bit A, u32bit& B, u32bit C, u32bit D, u32bit& E, u32bit msg)
   {
   E += (B ^ C ^ D) + msg + 0x6ED9EBA1 + rotate_left(A, 5);
   B  = rotate_left(B, 30);
   }

/*************************************************
* SHA-160 F3 Function                            *
*************************************************/
inline void F3(u32bit A, u32bit& B, u32bit C, u32bit D, u32bit& E, u32bit msg)
   {
   E += ((B & C) | ((B | C) & D)) + msg + 0x8F1BBCDC + rotate_left(A, 5);
   B  = rotate_left(B, 30);
   }

/*************************************************
* SHA-160 F4 Function                            *
*************************************************/
inline void F4(u32bit A, u32bit& B, u32bit C, u32bit D, u32bit& E, u32bit msg)
   {
   E += (B ^ C ^ D) + msg + 0xCA62C1D6 + rotate_left(A, 5);
   B  = rotate_left(B, 30);
   }

}

/*************************************************
* SHA-160 Compression Function                   *
*************************************************/
void SHA_160::hash(const byte input[])
   {
   for(u32bit j = 0; j != 16; ++j)
      W[j] = load_be<u32bit>(input, j);
   for(u32bit j = 16; j != 80; ++j)
      W[j] = rotate_left((W[j-3] ^ W[j-8] ^ W[j-14] ^ W[j-16]), 1);

   u32bit A = digest[0], B = digest[1], C = digest[2],
          D = digest[3], E = digest[4];

   F1(A,B,C,D,E,W[ 0]);   F1(E,A,B,C,D,W[ 1]);   F1(D,E,A,B,C,W[ 2]);
   F1(C,D,E,A,B,W[ 3]);   F1(B,C,D,E,A,W[ 4]);   F1(A,B,C,D,E,W[ 5]);
   F1(E,A,B,C,D,W[ 6]);   F1(D,E,A,B,C,W[ 7]);   F1(C,D,E,A,B,W[ 8]);
   F1(B,C,D,E,A,W[ 9]);   F1(A,B,C,D,E,W[10]);   F1(E,A,B,C,D,W[11]);
   F1(D,E,A,B,C,W[12]);   F1(C,D,E,A,B,W[13]);   F1(B,C,D,E,A,W[14]);
   F1(A,B,C,D,E,W[15]);   F1(E,A,B,C,D,W[16]);   F1(D,E,A,B,C,W[17]);
   F1(C,D,E,A,B,W[18]);   F1(B,C,D,E,A,W[19]);

   F2(A,B,C,D,E,W[20]);   F2(E,A,B,C,D,W[21]);   F2(D,E,A,B,C,W[22]);
   F2(C,D,E,A,B,W[23]);   F2(B,C,D,E,A,W[24]);   F2(A,B,C,D,E,W[25]);
   F2(E,A,B,C,D,W[26]);   F2(D,E,A,B,C,W[27]);   F2(C,D,E,A,B,W[28]);
   F2(B,C,D,E,A,W[29]);   F2(A,B,C,D,E,W[30]);   F2(E,A,B,C,D,W[31]);
   F2(D,E,A,B,C,W[32]);   F2(C,D,E,A,B,W[33]);   F2(B,C,D,E,A,W[34]);
   F2(A,B,C,D,E,W[35]);   F2(E,A,B,C,D,W[36]);   F2(D,E,A,B,C,W[37]);
   F2(C,D,E,A,B,W[38]);   F2(B,C,D,E,A,W[39]);

   F3(A,B,C,D,E,W[40]);   F3(E,A,B,C,D,W[41]);   F3(D,E,A,B,C,W[42]);
   F3(C,D,E,A,B,W[43]);   F3(B,C,D,E,A,W[44]);   F3(A,B,C,D,E,W[45]);
   F3(E,A,B,C,D,W[46]);   F3(D,E,A,B,C,W[47]);   F3(C,D,E,A,B,W[48]);
   F3(B,C,D,E,A,W[49]);   F3(A,B,C,D,E,W[50]);   F3(E,A,B,C,D,W[51]);
   F3(D,E,A,B,C,W[52]);   F3(C,D,E,A,B,W[53]);   F3(B,C,D,E,A,W[54]);
   F3(A,B,C,D,E,W[55]);   F3(E,A,B,C,D,W[56]);   F3(D,E,A,B,C,W[57]);
   F3(C,D,E,A,B,W[58]);   F3(B,C,D,E,A,W[59]);

   F4(A,B,C,D,E,W[60]);   F4(E,A,B,C,D,W[61]);   F4(D,E,A,B,C,W[62]);
   F4(C,D,E,A,B,W[63]);   F4(B,C,D,E,A,W[64]);   F4(A,B,C,D,E,W[65]);
   F4(E,A,B,C,D,W[66]);   F4(D,E,A,B,C,W[67]);   F4(C,D,E,A,B,W[68]);
   F4(B,C,D,E,A,W[69]);   F4(A,B,C,D,E,W[70]);   F4(E,A,B,C,D,W[71]);
   F4(D,E,A,B,C,W[72]);   F4(C,D,E,A,B,W[73]);   F4(B,C,D,E,A,W[74]);
   F4(A,B,C,D,E,W[75]);   F4(E,A,B,C,D,W[76]);   F4(D,E,A,B,C,W[77]);
   F4(C,D,E,A,B,W[78]);   F4(B,C,D,E,A,W[79]);

   digest[0] += A; digest[1] += B; digest[2] += C;
   digest[3] += D; digest[4] += E;
   }

/*************************************************
* Copy out the digest                            *
*************************************************/
void SHA_160::copy_out(byte output[])
   {
   for(u32bit j = 0; j != OUTPUT_LENGTH; j += 4)
      store_be(digest[j/4], output + j);
   }

/*************************************************
* Clear memory of sensitive data                 *
*************************************************/
void SHA_160::clear() throw()
   {
   MDx_HashFunction::clear();
   W.clear();
   digest[0] = 0x67452301;
   digest[1] = 0xEFCDAB89;
   digest[2] = 0x98BADCFE;
   digest[3] = 0x10325476;
   digest[4] = 0xC3D2E1F0;
   }

/*************************************************
* SHA_160 Constructor                            *
*************************************************/
SHA_160::SHA_160() : MDx_HashFunction(20, 64, true, true), W(80)
   {
   clear();
   }

}
<commit_msg>Unroll the loops in SHA_160::hash that unpack the input and perform the expansion. While I would prefer to have the compiler to this, using GCC 4.1.2 it is 4% faster on a Core2 Q6600 with the loops partially unrolled.<commit_after>/*************************************************
* SHA-160 Source File                            *
* (C) 1999-2008 The Botan Project                *
*************************************************/

#include <botan/sha160.h>
#include <botan/loadstor.h>
#include <botan/bit_ops.h>

namespace Botan {

namespace {

/*************************************************
* SHA-160 F1 Function                            *
*************************************************/
inline void F1(u32bit A, u32bit& B, u32bit C, u32bit D, u32bit& E, u32bit msg)
   {
   E += (D ^ (B & (C ^ D))) + msg + 0x5A827999 + rotate_left(A, 5);
   B  = rotate_left(B, 30);
   }

/*************************************************
* SHA-160 F2 Function                            *
*************************************************/
inline void F2(u32bit A, u32bit& B, u32bit C, u32bit D, u32bit& E, u32bit msg)
   {
   E += (B ^ C ^ D) + msg + 0x6ED9EBA1 + rotate_left(A, 5);
   B  = rotate_left(B, 30);
   }

/*************************************************
* SHA-160 F3 Function                            *
*************************************************/
inline void F3(u32bit A, u32bit& B, u32bit C, u32bit D, u32bit& E, u32bit msg)
   {
   E += ((B & C) | ((B | C) & D)) + msg + 0x8F1BBCDC + rotate_left(A, 5);
   B  = rotate_left(B, 30);
   }

/*************************************************
* SHA-160 F4 Function                            *
*************************************************/
inline void F4(u32bit A, u32bit& B, u32bit C, u32bit D, u32bit& E, u32bit msg)
   {
   E += (B ^ C ^ D) + msg + 0xCA62C1D6 + rotate_left(A, 5);
   B  = rotate_left(B, 30);
   }

}

/*************************************************
* SHA-160 Compression Function                   *
*************************************************/
void SHA_160::hash(const byte input[])
   {
   for(u32bit j = 0; j != 16; j += 4)
      {
      W[j  ] = load_be<u32bit>(input, j);
      W[j+1] = load_be<u32bit>(input, j+1);
      W[j+2] = load_be<u32bit>(input, j+2);
      W[j+3] = load_be<u32bit>(input, j+3);
      }

   for(u32bit j = 16; j != 80; j += 4)
      {
      W[j  ] = rotate_left((W[j-3] ^ W[j-8] ^ W[j-14] ^ W[j-16]), 1);
      W[j+1] = rotate_left((W[j-2] ^ W[j-7] ^ W[j-13] ^ W[j-15]), 1);
      W[j+2] = rotate_left((W[j-1] ^ W[j-6] ^ W[j-12] ^ W[j-14]), 1);
      W[j+3] = rotate_left((W[j  ] ^ W[j-5] ^ W[j-11] ^ W[j-13]), 1);
      }

   u32bit A = digest[0], B = digest[1], C = digest[2],
          D = digest[3], E = digest[4];

   F1(A,B,C,D,E,W[ 0]);   F1(E,A,B,C,D,W[ 1]);   F1(D,E,A,B,C,W[ 2]);
   F1(C,D,E,A,B,W[ 3]);   F1(B,C,D,E,A,W[ 4]);   F1(A,B,C,D,E,W[ 5]);
   F1(E,A,B,C,D,W[ 6]);   F1(D,E,A,B,C,W[ 7]);   F1(C,D,E,A,B,W[ 8]);
   F1(B,C,D,E,A,W[ 9]);   F1(A,B,C,D,E,W[10]);   F1(E,A,B,C,D,W[11]);
   F1(D,E,A,B,C,W[12]);   F1(C,D,E,A,B,W[13]);   F1(B,C,D,E,A,W[14]);
   F1(A,B,C,D,E,W[15]);   F1(E,A,B,C,D,W[16]);   F1(D,E,A,B,C,W[17]);
   F1(C,D,E,A,B,W[18]);   F1(B,C,D,E,A,W[19]);

   F2(A,B,C,D,E,W[20]);   F2(E,A,B,C,D,W[21]);   F2(D,E,A,B,C,W[22]);
   F2(C,D,E,A,B,W[23]);   F2(B,C,D,E,A,W[24]);   F2(A,B,C,D,E,W[25]);
   F2(E,A,B,C,D,W[26]);   F2(D,E,A,B,C,W[27]);   F2(C,D,E,A,B,W[28]);
   F2(B,C,D,E,A,W[29]);   F2(A,B,C,D,E,W[30]);   F2(E,A,B,C,D,W[31]);
   F2(D,E,A,B,C,W[32]);   F2(C,D,E,A,B,W[33]);   F2(B,C,D,E,A,W[34]);
   F2(A,B,C,D,E,W[35]);   F2(E,A,B,C,D,W[36]);   F2(D,E,A,B,C,W[37]);
   F2(C,D,E,A,B,W[38]);   F2(B,C,D,E,A,W[39]);

   F3(A,B,C,D,E,W[40]);   F3(E,A,B,C,D,W[41]);   F3(D,E,A,B,C,W[42]);
   F3(C,D,E,A,B,W[43]);   F3(B,C,D,E,A,W[44]);   F3(A,B,C,D,E,W[45]);
   F3(E,A,B,C,D,W[46]);   F3(D,E,A,B,C,W[47]);   F3(C,D,E,A,B,W[48]);
   F3(B,C,D,E,A,W[49]);   F3(A,B,C,D,E,W[50]);   F3(E,A,B,C,D,W[51]);
   F3(D,E,A,B,C,W[52]);   F3(C,D,E,A,B,W[53]);   F3(B,C,D,E,A,W[54]);
   F3(A,B,C,D,E,W[55]);   F3(E,A,B,C,D,W[56]);   F3(D,E,A,B,C,W[57]);
   F3(C,D,E,A,B,W[58]);   F3(B,C,D,E,A,W[59]);

   F4(A,B,C,D,E,W[60]);   F4(E,A,B,C,D,W[61]);   F4(D,E,A,B,C,W[62]);
   F4(C,D,E,A,B,W[63]);   F4(B,C,D,E,A,W[64]);   F4(A,B,C,D,E,W[65]);
   F4(E,A,B,C,D,W[66]);   F4(D,E,A,B,C,W[67]);   F4(C,D,E,A,B,W[68]);
   F4(B,C,D,E,A,W[69]);   F4(A,B,C,D,E,W[70]);   F4(E,A,B,C,D,W[71]);
   F4(D,E,A,B,C,W[72]);   F4(C,D,E,A,B,W[73]);   F4(B,C,D,E,A,W[74]);
   F4(A,B,C,D,E,W[75]);   F4(E,A,B,C,D,W[76]);   F4(D,E,A,B,C,W[77]);
   F4(C,D,E,A,B,W[78]);   F4(B,C,D,E,A,W[79]);

   digest[0] += A; digest[1] += B; digest[2] += C;
   digest[3] += D; digest[4] += E;
   }

/*************************************************
* Copy out the digest                            *
*************************************************/
void SHA_160::copy_out(byte output[])
   {
   for(u32bit j = 0; j != OUTPUT_LENGTH; j += 4)
      store_be(digest[j/4], output + j);
   }

/*************************************************
* Clear memory of sensitive data                 *
*************************************************/
void SHA_160::clear() throw()
   {
   MDx_HashFunction::clear();
   W.clear();
   digest[0] = 0x67452301;
   digest[1] = 0xEFCDAB89;
   digest[2] = 0x98BADCFE;
   digest[3] = 0x10325476;
   digest[4] = 0xC3D2E1F0;
   }

/*************************************************
* SHA_160 Constructor                            *
*************************************************/
SHA_160::SHA_160() : MDx_HashFunction(20, 64, true, true), W(80)
   {
   clear();
   }

}
<|endoftext|>


<commit_before>//===-- InstrinsicInst.cpp - Intrinsic Instruction Wrappers -----*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by James M. Laskey and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements methods that make it really easy to deal with intrinsic
// functions with the isa/dyncast family of functions.  In particular, this
// allows you to do things like:
//
//     if (DbgStopPointInst *SPI = dyn_cast<DbgStopPointInst>(Inst))
//        ... SPI->getFileName() ... SPI->getDirectory() ...
//
// All intrinsic function calls are instances of the call instruction, so these
// are all subclasses of the CallInst class.  Note that none of these classes
// has state or virtual methods, which is an important part of this gross/neat
// hack working.
//
// In some cases, arguments to intrinsics need to be generic and are defined as
// type pointer to empty struct { }*.  To access the real item of interest the
// cast instruction needs to be stripped away.
//
//===----------------------------------------------------------------------===//

#include "llvm/IntrinsicInst.h"

#include "llvm/Constants.h"
#include "llvm/GlobalVariable.h"

using namespace llvm;

//===----------------------------------------------------------------------===//
/// DbgInfoIntrinsic - This is the common base class for debug info intrinsics
///

static Value *CastOperand(Value *C) {
  if (ConstantExpr *CE = dyn_cast<ConstantExpr>(C))
    if (CE->getOpcode() == Instruction::Cast)
      return CE->getOperand(0);
  return NULL;
}

Value *DbgInfoIntrinsic::StripCast(Value *C) {
  if (Value *CO = CastOperand(C)) {
      return StripCast(CO);
  } else if (GlobalVariable *GV = dyn_cast<GlobalVariable>(C)) {
    if (GV->hasInitializer())
      if (Value *CO = CastOperand(GV->getInitializer()))
        return StripCast(CO);
  }
  return C;
}

//===----------------------------------------------------------------------===//
/// DbgStopPointInst - This represents the llvm.dbg.stoppoint instruction.
///

std::string DbgStopPointInst::getFileName() const {
  GlobalVariable *GV = cast<GlobalVariable>(getContext());
  ConstantStruct *CS = cast<ConstantStruct>(GV->getInitializer());
  return CS->getOperand(4)->getStringValue();
}

std::string DbgStopPointInst::getDirectory() const {
  GlobalVariable *GV = cast<GlobalVariable>(getContext());
  ConstantStruct *CS = cast<ConstantStruct>(GV->getInitializer());
  return CS->getOperand(5)->getStringValue();
}

//===----------------------------------------------------------------------===//
<commit_msg>Fix indent.<commit_after>//===-- InstrinsicInst.cpp - Intrinsic Instruction Wrappers -----*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by James M. Laskey and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements methods that make it really easy to deal with intrinsic
// functions with the isa/dyncast family of functions.  In particular, this
// allows you to do things like:
//
//     if (DbgStopPointInst *SPI = dyn_cast<DbgStopPointInst>(Inst))
//        ... SPI->getFileName() ... SPI->getDirectory() ...
//
// All intrinsic function calls are instances of the call instruction, so these
// are all subclasses of the CallInst class.  Note that none of these classes
// has state or virtual methods, which is an important part of this gross/neat
// hack working.
//
// In some cases, arguments to intrinsics need to be generic and are defined as
// type pointer to empty struct { }*.  To access the real item of interest the
// cast instruction needs to be stripped away.
//
//===----------------------------------------------------------------------===//

#include "llvm/IntrinsicInst.h"

#include "llvm/Constants.h"
#include "llvm/GlobalVariable.h"

using namespace llvm;

//===----------------------------------------------------------------------===//
/// DbgInfoIntrinsic - This is the common base class for debug info intrinsics
///

static Value *CastOperand(Value *C) {
  if (ConstantExpr *CE = dyn_cast<ConstantExpr>(C))
    if (CE->getOpcode() == Instruction::Cast)
      return CE->getOperand(0);
  return NULL;
}

Value *DbgInfoIntrinsic::StripCast(Value *C) {
  if (Value *CO = CastOperand(C)) {
    return StripCast(CO);
  } else if (GlobalVariable *GV = dyn_cast<GlobalVariable>(C)) {
    if (GV->hasInitializer())
      if (Value *CO = CastOperand(GV->getInitializer()))
        return StripCast(CO);
  }
  return C;
}

//===----------------------------------------------------------------------===//
/// DbgStopPointInst - This represents the llvm.dbg.stoppoint instruction.
///

std::string DbgStopPointInst::getFileName() const {
  GlobalVariable *GV = cast<GlobalVariable>(getContext());
  ConstantStruct *CS = cast<ConstantStruct>(GV->getInitializer());
  return CS->getOperand(4)->getStringValue();
}

std::string DbgStopPointInst::getDirectory() const {
  GlobalVariable *GV = cast<GlobalVariable>(getContext());
  ConstantStruct *CS = cast<ConstantStruct>(GV->getInitializer());
  return CS->getOperand(5)->getStringValue();
}

//===----------------------------------------------------------------------===//
<|endoftext|>


<commit_before>#include "PlatformId.h"

#include <string.h>

namespace PlatformIds
{
	const char* PlatformNames[PLATFORM_COUNT + 1] = {
		"unknown", // nothing set

		"3do",
		"amiga",
		"amstradcpc",
		"apple2",
		"arcade",
		"atari800",
		"atari2600",
		"atari5200",
		"atari7800",
		"atarilynx",
		"atarist",
		"atarijaguar",
		"atarijaguarcd",
		"atarixe",
		"bbcmicro",
		"colecovision",
		"c64", // commodore 64
		"intellivision",
		"macintosh",
		"xbox",
		"xbox360",
		"msx",
		"neogeo",
		"ngp", // neo geo pocket
		"ngpc", // neo geo pocket color
		"n3ds", // nintendo 3DS
		"n64", // nintendo 64
		"nds", // nintendo DS
		"fds", // Famicom Disk System
		"nes", // nintendo entertainment system
		"channelf", // Fairchild ChannelF
		"gb", // game boy
		"gba", // game boy advance
		"gbc", // game boy color
		"gc", // gamecube
		"wii",
		"wiiu",
		"virtualboy",
		"gameandwatch",
		"openbor",
		"pc",
		"sega32x",
		"segacd",
		"dreamcast",
		"gamegear",
		"genesis", // sega genesis
		"mastersystem", // sega master system
		"megadrive", // sega megadrive
		"saturn", // sega saturn
		"sg-1000",
		"psx",
		"ps2",
		"ps3",
		"ps4",
		"psvita",
		"psp", // playstation portable
		"snes", // super nintendo entertainment system
		"scummvm",
		"x1",
		"x68000",
		"solarus",
		"moto", // Thomson MO/TO
		"pc88", // NEC PC-8801
		"pc98", // NEC PC-9801
		"pcengine", // (aka turbografx-16) HuCards only
		"pcenginecd", // (aka turbografx-16) CD-ROMs only
		"wonderswan",
		"wonderswancolor",
		"zxspectrum",
		"zx81",
		"videopac",
		"vectrex",
		"trs-80",
		"coco",

		"ignore", // do not allow scraping for this system
		"invalid"
	};

	PlatformId getPlatformId(const char* str)
	{
		if(str == NULL)
			return PLATFORM_UNKNOWN;

		for(unsigned int i = 1; i < PLATFORM_COUNT; i++)
		{
			if(strcmp(PlatformNames[i], str) == 0)
				return (PlatformId)i;
		}

		return PLATFORM_UNKNOWN;
	}

	const char* getPlatformName(PlatformId id)
	{
		return PlatformNames[id];
	}
}
<commit_msg>scraper: add missing 'daphne' platform index<commit_after>#include "PlatformId.h"

#include <string.h>

namespace PlatformIds
{
	const char* PlatformNames[PLATFORM_COUNT + 1] = {
		"unknown", // nothing set

		"3do",
		"amiga",
		"amstradcpc",
		"apple2",
		"arcade",
		"atari800",
		"atari2600",
		"atari5200",
		"atari7800",
		"atarilynx",
		"atarist",
		"atarijaguar",
		"atarijaguarcd",
		"atarixe",
		"bbcmicro",
		"colecovision",
		"c64", // commodore 64
		"daphne",
		"intellivision",
		"macintosh",
		"xbox",
		"xbox360",
		"msx",
		"neogeo",
		"ngp", // neo geo pocket
		"ngpc", // neo geo pocket color
		"n3ds", // nintendo 3DS
		"n64", // nintendo 64
		"nds", // nintendo DS
		"fds", // Famicom Disk System
		"nes", // nintendo entertainment system
		"channelf", // Fairchild ChannelF
		"gb", // game boy
		"gba", // game boy advance
		"gbc", // game boy color
		"gc", // gamecube
		"wii",
		"wiiu",
		"virtualboy",
		"gameandwatch",
		"openbor",
		"pc",
		"sega32x",
		"segacd",
		"dreamcast",
		"gamegear",
		"genesis", // sega genesis
		"mastersystem", // sega master system
		"megadrive", // sega megadrive
		"saturn", // sega saturn
		"sg-1000",
		"psx",
		"ps2",
		"ps3",
		"ps4",
		"psvita",
		"psp", // playstation portable
		"snes", // super nintendo entertainment system
		"scummvm",
		"x1",
		"x68000",
		"solarus",
		"moto", // Thomson MO/TO
		"pc88", // NEC PC-8801
		"pc98", // NEC PC-9801
		"pcengine", // (aka turbografx-16) HuCards only
		"pcenginecd", // (aka turbografx-16) CD-ROMs only
		"wonderswan",
		"wonderswancolor",
		"zxspectrum",
		"zx81",
		"videopac",
		"vectrex",
		"trs-80",
		"coco",

		"ignore", // do not allow scraping for this system
		"invalid"
	};

	PlatformId getPlatformId(const char* str)
	{
		if(str == NULL)
			return PLATFORM_UNKNOWN;

		for(unsigned int i = 1; i < PLATFORM_COUNT; i++)
		{
			if(strcmp(PlatformNames[i], str) == 0)
				return (PlatformId)i;
		}

		return PLATFORM_UNKNOWN;
	}

	const char* getPlatformName(PlatformId id)
	{
		return PlatformNames[id];
	}
}
<|endoftext|>


<commit_before>// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/file_path.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/browser_window.h"
#include "chrome/browser/defaults.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/test/in_process_browser_test.h"
#include "chrome/test/ui_test_utils.h"

typedef InProcessBrowserTest SessionRestoreTest;

#if defined(OS_LINUX) && defined(TOOLKIT_VIEWS)
// http://crbug.com/39476
#define MAYBE_RestoreOnNewWindowWithNoTabbedBrowsers \
        FAILS_RestoreOnNewWindowWithNoTabbedBrowsers
#else
#define MAYBE_RestoreOnNewWindowWithNoTabbedBrowsers \
        RestoreOnNewWindowWithNoTabbedBrowsers
#endif

// Makes sure when session restore is triggered in the same process we don't end
// up with an extra tab.
IN_PROC_BROWSER_TEST_F(SessionRestoreTest,
                       MAYBE_RestoreOnNewWindowWithNoTabbedBrowsers) {
  if (browser_defaults::kRestorePopups)
    return;

  const FilePath::CharType* kTitle1File = FILE_PATH_LITERAL("title1.html");
  GURL url(ui_test_utils::GetTestUrl(FilePath(FilePath::kCurrentDirectory),
                                     FilePath(kTitle1File)));
  ui_test_utils::NavigateToURL(browser(), url);

  // Turn on session restore.
  SessionStartupPref::SetStartupPref(
      browser()->profile(),
      SessionStartupPref(SessionStartupPref::LAST));

  // Create a new popup.
  Profile* profile = browser()->profile();
  Browser* popup = Browser::CreateForPopup(profile);
  popup->window()->Show();

  // Close the browser.
  browser()->window()->Close();

  // Create a new window, which should trigger session restore.
  popup->NewWindow();

  Browser* new_browser = ui_test_utils::WaitForNewBrowser();

  ASSERT_TRUE(new_browser != NULL);

  // The browser should only have one tab.
  ASSERT_EQ(1, new_browser->tab_count());

  // And the first url should be url.
  EXPECT_EQ(url, new_browser->GetTabContentsAt(0)->GetURL());
}
<commit_msg>RestoreOnNewWindowWithNoTabbedBrowsers actually needs to be DISABLED_ not just FAILS_ because it crashes.<commit_after>// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/file_path.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/browser_window.h"
#include "chrome/browser/defaults.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/test/in_process_browser_test.h"
#include "chrome/test/ui_test_utils.h"

typedef InProcessBrowserTest SessionRestoreTest;

#if defined(OS_LINUX) && defined(TOOLKIT_VIEWS)
// Crashes on Linux Views: http://crbug.com/39476
#define MAYBE_RestoreOnNewWindowWithNoTabbedBrowsers \
        DISABLED_RestoreOnNewWindowWithNoTabbedBrowsers
#else
#define MAYBE_RestoreOnNewWindowWithNoTabbedBrowsers \
        RestoreOnNewWindowWithNoTabbedBrowsers
#endif

// Makes sure when session restore is triggered in the same process we don't end
// up with an extra tab.
IN_PROC_BROWSER_TEST_F(SessionRestoreTest,
                       MAYBE_RestoreOnNewWindowWithNoTabbedBrowsers) {
  if (browser_defaults::kRestorePopups)
    return;

  const FilePath::CharType* kTitle1File = FILE_PATH_LITERAL("title1.html");
  GURL url(ui_test_utils::GetTestUrl(FilePath(FilePath::kCurrentDirectory),
                                     FilePath(kTitle1File)));
  ui_test_utils::NavigateToURL(browser(), url);

  // Turn on session restore.
  SessionStartupPref::SetStartupPref(
      browser()->profile(),
      SessionStartupPref(SessionStartupPref::LAST));

  // Create a new popup.
  Profile* profile = browser()->profile();
  Browser* popup = Browser::CreateForPopup(profile);
  popup->window()->Show();

  // Close the browser.
  browser()->window()->Close();

  // Create a new window, which should trigger session restore.
  popup->NewWindow();

  Browser* new_browser = ui_test_utils::WaitForNewBrowser();

  ASSERT_TRUE(new_browser != NULL);

  // The browser should only have one tab.
  ASSERT_EQ(1, new_browser->tab_count());

  // And the first url should be url.
  EXPECT_EQ(url, new_browser->GetTabContentsAt(0)->GetURL());
}
<|endoftext|>


<commit_before><commit_msg>Now typed url code VLOGs on duplicate visits instead of warnings.<commit_after><|endoftext|>