<commit_before>/*
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Library General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 *
 * DummyPlugin.cpp
 * The Dummy plugin for ola, contains a single dummy device
 * Copyright (C) 2005-2007 Simon Newton
 */

#include <stdlib.h>
#include <stdio.h>
#include <string>

#include "olad/PluginAdaptor.h"
#include "plugins/dummy/DummyDevice.h"
#include "plugins/dummy/DummyPlugin.h"

/*
 * Entry point to this plugin
 */
extern "C" ola::AbstractPlugin* create(
    const ola::PluginAdaptor *plugin_adaptor) {
  return new ola::plugin::dummy::DummyPlugin(plugin_adaptor);
}

namespace ola {
namespace plugin {
namespace dummy {

using std::string;

const char DummyPlugin::PLUGIN_NAME[] = "Dummy";
const char DummyPlugin::PLUGIN_PREFIX[] = "dummy";
const char DummyPlugin::DEVICE_NAME[] = "Dummy Device";

/*
 * Start the plugin
 *
 * Lets keep it simple, one device for this plugin
 */
bool DummyPlugin::StartHook() {
  m_device = new DummyDevice(this, DEVICE_NAME);
  m_device->Start();
  m_plugin_adaptor->RegisterDevice(m_device);
  return true;
}

/*
 * Stop the plugin
 * @return true on sucess, false on failure
 */
bool DummyPlugin::StopHook() {
  if (m_device) {
    m_plugin_adaptor->UnregisterDevice(m_device);
    bool ret = m_device->Stop();
    delete m_device;
    return ret;
  }
  return true;
}

string DummyPlugin::Description() const {
  return
"Dummy Plugin\n"
"----------------------------\n"
"\n"
"The plugin creates a single device with one port. "
"When used as an output port it prints the first two bytes of dmx data to "
"stdout.\n\n"
"It also emulates a simple RDM device which can be querried and the DMX\n"
"start address can be changed.\n";
}
}  // dummy
}  // plugin
}  // ola
<commit_msg> * clean up the dummy docs<commit_after>/*
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Library General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 *
 * DummyPlugin.cpp
 * The Dummy plugin for ola, contains a single dummy device
 * Copyright (C) 2005-2007 Simon Newton
 */

#include <stdlib.h>
#include <stdio.h>
#include <string>

#include "olad/PluginAdaptor.h"
#include "plugins/dummy/DummyDevice.h"
#include "plugins/dummy/DummyPlugin.h"

/*
 * Entry point to this plugin
 */
extern "C" ola::AbstractPlugin* create(
    const ola::PluginAdaptor *plugin_adaptor) {
  return new ola::plugin::dummy::DummyPlugin(plugin_adaptor);
}

namespace ola {
namespace plugin {
namespace dummy {

using std::string;

const char DummyPlugin::PLUGIN_NAME[] = "Dummy";
const char DummyPlugin::PLUGIN_PREFIX[] = "dummy";
const char DummyPlugin::DEVICE_NAME[] = "Dummy Device";

/*
 * Start the plugin
 *
 * Lets keep it simple, one device for this plugin
 */
bool DummyPlugin::StartHook() {
  m_device = new DummyDevice(this, DEVICE_NAME);
  m_device->Start();
  m_plugin_adaptor->RegisterDevice(m_device);
  return true;
}

/*
 * Stop the plugin
 * @return true on sucess, false on failure
 */
bool DummyPlugin::StopHook() {
  if (m_device) {
    m_plugin_adaptor->UnregisterDevice(m_device);
    bool ret = m_device->Stop();
    delete m_device;
    return ret;
  }
  return true;
}

string DummyPlugin::Description() const {
  return
"Dummy Plugin\n"
"----------------------------\n"
"\n"
"The plugin creates a single device with one port. When used as an output\n"
"port it prints the first two bytes of dmx data to stdout.\n\n"
"It also creates a fake RDM device which can be querried and the DMX start\n"
"address can be changed.\n";
}
}  // dummy
}  // plugin
}  // ola
<|endoftext|>


<commit_before>//===--- Type.cpp - Swift Language Type ASTs ------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
//  This file implements the Type class and subclasses.
//
//===----------------------------------------------------------------------===//

#include "swift/AST/Types.h"
#include "swift/AST/AST.h"
#include "llvm/ADT/APFloat.h"
#include "llvm/Support/raw_ostream.h"
using namespace swift;

// Only allow allocation of Stmts using the allocator in ASTContext.
void *TypeBase::operator new(size_t Bytes, ASTContext &C,
                         unsigned Alignment) throw() {
  return C.Allocate(Bytes, Alignment);
}

//===----------------------------------------------------------------------===//
// Various Type Methods.
//===----------------------------------------------------------------------===//

/// isEqual - Return true if these two types are equal, ignoring sugar.
bool TypeBase::isEqual(Type Other) {
  return getCanonicalType() == Other.getPointer()->getCanonicalType();
}

/// isMaterializable - Is this type 'materializable' according to the
/// rules of the language?  Basically, does it not contain any l-value
/// types?
bool TypeBase::isMaterializable() {
  if (TupleType *tuple = getAs<TupleType>()) {
    for (auto &field : tuple->getFields())
      if (!field.getType()->isMaterializable())
        return false;
    return true;
  }

  return !is<LValueType>();
}

/// getCanonicalType - Return the canonical version of this type, which has
/// sugar from all levels stripped off.
TypeBase *TypeBase::getCanonicalType() {
  assert(this != 0 &&
         "Cannot call getCanonicalType before name binding is complete");

  // If the type is itself canonical, return it.
  if (CanonicalType.is<ASTContext*>())
    return this;
  // If the canonical type was already computed, just return what we have.
  if (TypeBase *CT = CanonicalType.get<TypeBase*>())
    return CT;

  // Otherwise, compute and cache it.
  TypeBase *Result = 0;
  switch (getKind()) {
#define ALWAYS_CANONICAL_TYPE(id, parent) case TypeKind::id:
#define UNCHECKED_TYPE(id, parent) case TypeKind::id:
#define TYPE(id, parent)
#include "swift/AST/TypeNodes.def"
    llvm_unreachable("these types are always canonical");

#define SUGARED_TYPE(id, parent) \
  case TypeKind::id: \
    Result = cast<id##Type>(this)->getDesugaredType()->getCanonicalType(); \
    break;
#define TYPE(id, parent)
#include "swift/AST/TypeNodes.def"

  case TypeKind::Tuple: {
    TupleType *TT = cast<TupleType>(this);
    assert(!TT->getFields().empty() && "Empty tuples are always canonical");

    SmallVector<TupleTypeElt, 8> CanElts;
    CanElts.reserve(TT->getFields().size());
    for (const TupleTypeElt &field : TT->getFields()) {
      assert(!field.getType().isNull() &&
             "Cannot get canonical type of un-typechecked TupleType!");
      CanElts.push_back(TupleTypeElt(field.getType()->getCanonicalType(),
                                     field.getName()));
    }

    Result = TupleType::get(CanElts, CanElts[0].getType()->getASTContext());
    break;
  }

  case TypeKind::LValue: {
    LValueType *lvalue = cast<LValueType>(this);
    Type objectType = lvalue->getObjectType();
    objectType = objectType->getCanonicalType();
    Result = LValueType::get(objectType, lvalue->getQualifiers(),
                             objectType->getASTContext());
    break;
  }
  case TypeKind::Function: {
    FunctionType *FT = cast<FunctionType>(this);
    Type In = FT->getInput()->getCanonicalType();
    Type Out = FT->getResult()->getCanonicalType();
    Result = FunctionType::get(In, Out, FT->isAutoClosure(),
                               In->getASTContext());
    break;
  }
  case TypeKind::Array:
    ArrayType *AT = cast<ArrayType>(this);
    Type EltTy = AT->getBaseType()->getCanonicalType();
    Result = ArrayType::get(EltTy, AT->getSize(), EltTy->getASTContext());
    break;
  }

  // Cache the canonical type for future queries.
  assert(Result && "Case not implemented!");
  CanonicalType = Result;
  return Result;
}

TypeBase *TypeBase::getDesugaredType() {
  switch (getKind()) {
#define ALWAYS_CANONICAL_TYPE(id, parent) case TypeKind::id:
#define UNCHECKED_TYPE(id, parent) case TypeKind::id:
#define TYPE(id, parent)
#include "swift/AST/TypeNodes.def"
  case TypeKind::Tuple:
  case TypeKind::Function:
  case TypeKind::Array:
  case TypeKind::LValue:
    // None of these types have sugar at the outer level.
    return this;
  case TypeKind::Paren:
    return cast<ParenType>(this)->getDesugaredType();
  case TypeKind::Identifier:
    return cast<IdentifierType>(this)->getDesugaredType();
  case TypeKind::NameAlias:
    return cast<NameAliasType>(this)->getDesugaredType();
  }

  llvm_unreachable("Unknown type kind");
}

TypeBase *ParenType::getDesugaredType() {
  return getUnderlyingType()->getDesugaredType();
}

TypeBase *NameAliasType::getDesugaredType() {
  return getDecl()->getUnderlyingType()->getDesugaredType();
}

TypeBase *IdentifierType::getDesugaredType() {
  return getMappedType()->getDesugaredType();
}

const llvm::fltSemantics &BuiltinFloatType::getAPFloatSemantics() const {
  switch (getFPKind()) {
  case BuiltinFloatType::IEEE16:  return APFloat::IEEEhalf;
  case BuiltinFloatType::IEEE32:  return APFloat::IEEEsingle;
  case BuiltinFloatType::IEEE64:  return APFloat::IEEEdouble;
  case BuiltinFloatType::IEEE80:  return APFloat::x87DoubleExtended;
  case BuiltinFloatType::IEEE128: return APFloat::IEEEquad;
  case BuiltinFloatType::PPC128:  return APFloat::PPCDoubleDouble;
  }
  assert(0 && "Unknown FP semantics");
  return APFloat::IEEEhalf;
}

Type IdentifierType::getMappedType() {
  assert(!Components.back().Value.isNull() &&
         "Name binding haven't resolved this to a type yet");
  return Components.back().Value.get<TypeBase*>();
}

/// hasAnyDefaultValues - Return true if any of our elements has a default
/// value.
bool TupleType::hasAnyDefaultValues() const {
  for (const TupleTypeElt &Elt : Fields)
    if (Elt.hasInit())
      return true;
  return false;
}

/// getNamedElementId - If this tuple has a field with the specified name,
/// return the field index, otherwise return -1.
int TupleType::getNamedElementId(Identifier I) const {
  for (unsigned i = 0, e = Fields.size(); i != e; ++i) {
    if (Fields[i].getName() == I)
      return i;
  }

  // Otherwise, name not found.
  return -1;
}

/// getFieldForScalarInit - If a tuple of this type can be initialized with a
/// scalar, return the field number that the scalar is assigned to.  If not,
/// return -1.
int TupleType::getFieldForScalarInit() const {
  if (Fields.empty()) return -1;

  int FieldWithoutDefault = -1;
  for (unsigned i = 0, e = Fields.size(); i != e; ++i) {
    // Ignore fields with a default value.
    if (Fields[i].hasInit()) continue;

    // If we already saw a field missing a default value, then we cannot assign
    // a scalar to this tuple.
    if (FieldWithoutDefault != -1)
      return -1;

    // Otherwise, remember this field number.
    FieldWithoutDefault = i;
  }

  // If all the elements have default values, the scalar initializes the first
  // value in the tuple.
  return FieldWithoutDefault == -1 ? 0 : FieldWithoutDefault;
}

/// updateInitializedElementType - This methods updates the element type and
/// initializer for a non-canonical TupleType that has an initializer for the
/// specified element.  This should only be used by TypeChecker.
void TupleType::updateInitializedElementType(unsigned EltNo, Type NewTy,
                                             Expr *NewInit) {
  assert(!hasCanonicalTypeComputed() &&
         "Cannot munge an already canonicalized type!");
  TupleTypeElt &Elt = const_cast<TupleTypeElt&>(Fields[EltNo]);
  assert(Elt.hasInit() && "Can only update elements with default values");
  Elt = TupleTypeElt(NewTy, Elt.getName(), NewInit);
}

OneOfElementDecl *OneOfType::getElement(Identifier Name) const {
  // FIXME: Linear search is not great for large oneof decls.
  for (OneOfElementDecl *Elt : Elements)
    if (Elt->getName() == Name)
      return Elt;
  return 0;
}

bool OneOfType::isTransparentType() const {
  return Elements.size() == 1 && !Elements[0]->getArgumentType().isNull();
}

Type OneOfType::getTransparentType() const {
  assert(Elements.size() == 1);
  assert(!Elements[0]->getArgumentType().isNull());
  return Elements[0]->getArgumentType();
}

//===----------------------------------------------------------------------===//
//  Type Printing
//===----------------------------------------------------------------------===//

void Type::dump() const {
  print(llvm::errs());
  llvm::errs() << '\n';
}
void Type::print(raw_ostream &OS) const {
  if (isNull())
    OS << "<null>";
  else
    Ptr->print(OS);
}

/// getString - Return the name of the type as a string, for use in
/// diagnostics only.
std::string Type::getString() const {
  std::string Result;
  llvm::raw_string_ostream OS(Result);
  print(OS);
  return OS.str();
}

/// getString - Return the name of the type as a string, for use in
/// diagnostics only.
std::string TypeBase::getString() const {
  std::string Result;
  llvm::raw_string_ostream OS(Result);
  print(OS);
  return OS.str();
}

void TypeBase::dump() const {
  print(llvm::errs());
  llvm::errs() << '\n';
}

void TypeBase::print(raw_ostream &OS) const {
  switch (getKind()) {
#define TYPE(id, parent) \
  case TypeKind::id:            return cast<id##Type>(this)->print(OS);
#include "swift/AST/TypeNodes.def"
  }
  llvm_unreachable("bad type kind!");
}

void BuiltinIntegerType::print(raw_ostream &OS) const {
  OS << "Builtin::int" << cast<BuiltinIntegerType>(this)->getBitWidth();
}

void BuiltinFloatType::print(raw_ostream &OS) const {
  switch (getFPKind()) {
  case IEEE16:  OS << "Builtin::FP_IEEE16"; return;
  case IEEE32:  OS << "Builtin::FP_IEEE32"; return;
  case IEEE64:  OS << "Builtin::FP_IEEE64"; return;
  case IEEE80:  OS << "Builtin::FP_IEEE80"; return;
  case IEEE128: OS << "Builtin::FP_IEEE128"; return;
  case PPC128:  OS << "Builtin::FP_PPC128"; return;
  }
}

void ErrorType::print(raw_ostream &OS) const {
  OS << "<<error type>>";
}

void DependentType::print(raw_ostream &OS) const {
  OS << "<<dependent type>>";
}

void ParenType::print(raw_ostream &OS) const {
  OS << '(';
  UnderlyingType->print(OS);
  OS << ')';
}

void NameAliasType::print(raw_ostream &OS) const {
  OS << TheDecl->getName().get();
}

void IdentifierType::print(raw_ostream &OS) const {
  OS << Components[0].Id.get();

  for (const Component &C : Components.slice(1, Components.size()-1))
    OS << '.' << C.Id.get();
}

void OneOfType::print(raw_ostream &OS) const {
  OS << "oneof { ";

  for (unsigned i = 0, e = Elements.size(); i != e; ++i) {
    if (i) OS << ", ";
    OS << Elements[i]->getName();
    if (!Elements[i]->getArgumentType().isNull())
      OS << " : " << Elements[i]->getArgumentType();
  }

  OS << '}';
}

void MetaTypeType::print(raw_ostream &OS) const {
  OS << "metatype<" << TheType->getName() << '>';
}

void ModuleType::print(raw_ostream &OS) const {
  OS << "module<" << TheModule->Name << '>';
}

void TupleType::print(raw_ostream &OS) const {
  OS << "(";

  for (unsigned i = 0, e = Fields.size(); i != e; ++i) {
    if (i) OS << ", ";
    const TupleTypeElt &TD = Fields[i];

    if (TD.hasName())
      OS << TD.getName() << " : ";

    OS << TD.getType();
  }
  OS << ')';
}

void FunctionType::print(raw_ostream &OS) const {
  if (isAutoClosure())
    OS << "[auto_closure]";
  OS << Input << " -> " << Result;
}

void ArrayType::print(raw_ostream &OS) const {
  OS << Base << '[';
  if (Size)
    OS << Size;
  OS << ']';
}

void ProtocolType::print(raw_ostream &OS) const {
  OS << "protocol {";
  for (Decl *D : Elements)
    D->print(OS);
  OS << '}';
}

void LValueType::print(raw_ostream &OS) const {
  OS << "[byref";

  Qual qs = getQualifiers();
  if (qs & (Qual::Implicit)) {
    OS << '(';
    if (qs & Qual::Implicit) OS << "implicit";
    OS << ')';
  }
  OS << "] ";
  getObjectType()->print(OS);
}
<commit_msg>Fix pretty-printing of builtin types:  we use . instead :: now.<commit_after>//===--- Type.cpp - Swift Language Type ASTs ------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
//  This file implements the Type class and subclasses.
//
//===----------------------------------------------------------------------===//

#include "swift/AST/Types.h"
#include "swift/AST/AST.h"
#include "llvm/ADT/APFloat.h"
#include "llvm/Support/raw_ostream.h"
using namespace swift;

// Only allow allocation of Stmts using the allocator in ASTContext.
void *TypeBase::operator new(size_t Bytes, ASTContext &C,
                         unsigned Alignment) throw() {
  return C.Allocate(Bytes, Alignment);
}

//===----------------------------------------------------------------------===//
// Various Type Methods.
//===----------------------------------------------------------------------===//

/// isEqual - Return true if these two types are equal, ignoring sugar.
bool TypeBase::isEqual(Type Other) {
  return getCanonicalType() == Other.getPointer()->getCanonicalType();
}

/// isMaterializable - Is this type 'materializable' according to the
/// rules of the language?  Basically, does it not contain any l-value
/// types?
bool TypeBase::isMaterializable() {
  if (TupleType *tuple = getAs<TupleType>()) {
    for (auto &field : tuple->getFields())
      if (!field.getType()->isMaterializable())
        return false;
    return true;
  }

  return !is<LValueType>();
}

/// getCanonicalType - Return the canonical version of this type, which has
/// sugar from all levels stripped off.
TypeBase *TypeBase::getCanonicalType() {
  assert(this != 0 &&
         "Cannot call getCanonicalType before name binding is complete");

  // If the type is itself canonical, return it.
  if (CanonicalType.is<ASTContext*>())
    return this;
  // If the canonical type was already computed, just return what we have.
  if (TypeBase *CT = CanonicalType.get<TypeBase*>())
    return CT;

  // Otherwise, compute and cache it.
  TypeBase *Result = 0;
  switch (getKind()) {
#define ALWAYS_CANONICAL_TYPE(id, parent) case TypeKind::id:
#define UNCHECKED_TYPE(id, parent) case TypeKind::id:
#define TYPE(id, parent)
#include "swift/AST/TypeNodes.def"
    llvm_unreachable("these types are always canonical");

#define SUGARED_TYPE(id, parent) \
  case TypeKind::id: \
    Result = cast<id##Type>(this)->getDesugaredType()->getCanonicalType(); \
    break;
#define TYPE(id, parent)
#include "swift/AST/TypeNodes.def"

  case TypeKind::Tuple: {
    TupleType *TT = cast<TupleType>(this);
    assert(!TT->getFields().empty() && "Empty tuples are always canonical");

    SmallVector<TupleTypeElt, 8> CanElts;
    CanElts.reserve(TT->getFields().size());
    for (const TupleTypeElt &field : TT->getFields()) {
      assert(!field.getType().isNull() &&
             "Cannot get canonical type of un-typechecked TupleType!");
      CanElts.push_back(TupleTypeElt(field.getType()->getCanonicalType(),
                                     field.getName()));
    }

    Result = TupleType::get(CanElts, CanElts[0].getType()->getASTContext());
    break;
  }

  case TypeKind::LValue: {
    LValueType *lvalue = cast<LValueType>(this);
    Type objectType = lvalue->getObjectType();
    objectType = objectType->getCanonicalType();
    Result = LValueType::get(objectType, lvalue->getQualifiers(),
                             objectType->getASTContext());
    break;
  }
  case TypeKind::Function: {
    FunctionType *FT = cast<FunctionType>(this);
    Type In = FT->getInput()->getCanonicalType();
    Type Out = FT->getResult()->getCanonicalType();
    Result = FunctionType::get(In, Out, FT->isAutoClosure(),
                               In->getASTContext());
    break;
  }
  case TypeKind::Array:
    ArrayType *AT = cast<ArrayType>(this);
    Type EltTy = AT->getBaseType()->getCanonicalType();
    Result = ArrayType::get(EltTy, AT->getSize(), EltTy->getASTContext());
    break;
  }

  // Cache the canonical type for future queries.
  assert(Result && "Case not implemented!");
  CanonicalType = Result;
  return Result;
}

TypeBase *TypeBase::getDesugaredType() {
  switch (getKind()) {
#define ALWAYS_CANONICAL_TYPE(id, parent) case TypeKind::id:
#define UNCHECKED_TYPE(id, parent) case TypeKind::id:
#define TYPE(id, parent)
#include "swift/AST/TypeNodes.def"
  case TypeKind::Tuple:
  case TypeKind::Function:
  case TypeKind::Array:
  case TypeKind::LValue:
    // None of these types have sugar at the outer level.
    return this;
  case TypeKind::Paren:
    return cast<ParenType>(this)->getDesugaredType();
  case TypeKind::Identifier:
    return cast<IdentifierType>(this)->getDesugaredType();
  case TypeKind::NameAlias:
    return cast<NameAliasType>(this)->getDesugaredType();
  }

  llvm_unreachable("Unknown type kind");
}

TypeBase *ParenType::getDesugaredType() {
  return getUnderlyingType()->getDesugaredType();
}

TypeBase *NameAliasType::getDesugaredType() {
  return getDecl()->getUnderlyingType()->getDesugaredType();
}

TypeBase *IdentifierType::getDesugaredType() {
  return getMappedType()->getDesugaredType();
}

const llvm::fltSemantics &BuiltinFloatType::getAPFloatSemantics() const {
  switch (getFPKind()) {
  case BuiltinFloatType::IEEE16:  return APFloat::IEEEhalf;
  case BuiltinFloatType::IEEE32:  return APFloat::IEEEsingle;
  case BuiltinFloatType::IEEE64:  return APFloat::IEEEdouble;
  case BuiltinFloatType::IEEE80:  return APFloat::x87DoubleExtended;
  case BuiltinFloatType::IEEE128: return APFloat::IEEEquad;
  case BuiltinFloatType::PPC128:  return APFloat::PPCDoubleDouble;
  }
  assert(0 && "Unknown FP semantics");
  return APFloat::IEEEhalf;
}

Type IdentifierType::getMappedType() {
  assert(!Components.back().Value.isNull() &&
         "Name binding haven't resolved this to a type yet");
  return Components.back().Value.get<TypeBase*>();
}

/// hasAnyDefaultValues - Return true if any of our elements has a default
/// value.
bool TupleType::hasAnyDefaultValues() const {
  for (const TupleTypeElt &Elt : Fields)
    if (Elt.hasInit())
      return true;
  return false;
}

/// getNamedElementId - If this tuple has a field with the specified name,
/// return the field index, otherwise return -1.
int TupleType::getNamedElementId(Identifier I) const {
  for (unsigned i = 0, e = Fields.size(); i != e; ++i) {
    if (Fields[i].getName() == I)
      return i;
  }

  // Otherwise, name not found.
  return -1;
}

/// getFieldForScalarInit - If a tuple of this type can be initialized with a
/// scalar, return the field number that the scalar is assigned to.  If not,
/// return -1.
int TupleType::getFieldForScalarInit() const {
  if (Fields.empty()) return -1;

  int FieldWithoutDefault = -1;
  for (unsigned i = 0, e = Fields.size(); i != e; ++i) {
    // Ignore fields with a default value.
    if (Fields[i].hasInit()) continue;

    // If we already saw a field missing a default value, then we cannot assign
    // a scalar to this tuple.
    if (FieldWithoutDefault != -1)
      return -1;

    // Otherwise, remember this field number.
    FieldWithoutDefault = i;
  }

  // If all the elements have default values, the scalar initializes the first
  // value in the tuple.
  return FieldWithoutDefault == -1 ? 0 : FieldWithoutDefault;
}

/// updateInitializedElementType - This methods updates the element type and
/// initializer for a non-canonical TupleType that has an initializer for the
/// specified element.  This should only be used by TypeChecker.
void TupleType::updateInitializedElementType(unsigned EltNo, Type NewTy,
                                             Expr *NewInit) {
  assert(!hasCanonicalTypeComputed() &&
         "Cannot munge an already canonicalized type!");
  TupleTypeElt &Elt = const_cast<TupleTypeElt&>(Fields[EltNo]);
  assert(Elt.hasInit() && "Can only update elements with default values");
  Elt = TupleTypeElt(NewTy, Elt.getName(), NewInit);
}

OneOfElementDecl *OneOfType::getElement(Identifier Name) const {
  // FIXME: Linear search is not great for large oneof decls.
  for (OneOfElementDecl *Elt : Elements)
    if (Elt->getName() == Name)
      return Elt;
  return 0;
}

bool OneOfType::isTransparentType() const {
  return Elements.size() == 1 && !Elements[0]->getArgumentType().isNull();
}

Type OneOfType::getTransparentType() const {
  assert(Elements.size() == 1);
  assert(!Elements[0]->getArgumentType().isNull());
  return Elements[0]->getArgumentType();
}

//===----------------------------------------------------------------------===//
//  Type Printing
//===----------------------------------------------------------------------===//

void Type::dump() const {
  print(llvm::errs());
  llvm::errs() << '\n';
}
void Type::print(raw_ostream &OS) const {
  if (isNull())
    OS << "<null>";
  else
    Ptr->print(OS);
}

/// getString - Return the name of the type as a string, for use in
/// diagnostics only.
std::string Type::getString() const {
  std::string Result;
  llvm::raw_string_ostream OS(Result);
  print(OS);
  return OS.str();
}

/// getString - Return the name of the type as a string, for use in
/// diagnostics only.
std::string TypeBase::getString() const {
  std::string Result;
  llvm::raw_string_ostream OS(Result);
  print(OS);
  return OS.str();
}

void TypeBase::dump() const {
  print(llvm::errs());
  llvm::errs() << '\n';
}

void TypeBase::print(raw_ostream &OS) const {
  switch (getKind()) {
#define TYPE(id, parent) \
  case TypeKind::id:            return cast<id##Type>(this)->print(OS);
#include "swift/AST/TypeNodes.def"
  }
  llvm_unreachable("bad type kind!");
}

void BuiltinIntegerType::print(raw_ostream &OS) const {
  OS << "Builtin.int" << cast<BuiltinIntegerType>(this)->getBitWidth();
}

void BuiltinFloatType::print(raw_ostream &OS) const {
  switch (getFPKind()) {
  case IEEE16:  OS << "Builtin.FP_IEEE16"; return;
  case IEEE32:  OS << "Builtin.FP_IEEE32"; return;
  case IEEE64:  OS << "Builtin.FP_IEEE64"; return;
  case IEEE80:  OS << "Builtin.FP_IEEE80"; return;
  case IEEE128: OS << "Builtin.FP_IEEE128"; return;
  case PPC128:  OS << "Builtin.FP_PPC128"; return;
  }
}

void ErrorType::print(raw_ostream &OS) const {
  OS << "<<error type>>";
}

void DependentType::print(raw_ostream &OS) const {
  OS << "<<dependent type>>";
}

void ParenType::print(raw_ostream &OS) const {
  OS << '(';
  UnderlyingType->print(OS);
  OS << ')';
}

void NameAliasType::print(raw_ostream &OS) const {
  OS << TheDecl->getName().get();
}

void IdentifierType::print(raw_ostream &OS) const {
  OS << Components[0].Id.get();

  for (const Component &C : Components.slice(1, Components.size()-1))
    OS << '.' << C.Id.get();
}

void OneOfType::print(raw_ostream &OS) const {
  OS << "oneof { ";

  for (unsigned i = 0, e = Elements.size(); i != e; ++i) {
    if (i) OS << ", ";
    OS << Elements[i]->getName();
    if (!Elements[i]->getArgumentType().isNull())
      OS << " : " << Elements[i]->getArgumentType();
  }

  OS << '}';
}

void MetaTypeType::print(raw_ostream &OS) const {
  OS << "metatype<" << TheType->getName() << '>';
}

void ModuleType::print(raw_ostream &OS) const {
  OS << "module<" << TheModule->Name << '>';
}

void TupleType::print(raw_ostream &OS) const {
  OS << "(";

  for (unsigned i = 0, e = Fields.size(); i != e; ++i) {
    if (i) OS << ", ";
    const TupleTypeElt &TD = Fields[i];

    if (TD.hasName())
      OS << TD.getName() << " : ";

    OS << TD.getType();
  }
  OS << ')';
}

void FunctionType::print(raw_ostream &OS) const {
  if (isAutoClosure())
    OS << "[auto_closure]";
  OS << Input << " -> " << Result;
}

void ArrayType::print(raw_ostream &OS) const {
  OS << Base << '[';
  if (Size)
    OS << Size;
  OS << ']';
}

void ProtocolType::print(raw_ostream &OS) const {
  OS << "protocol {";
  for (Decl *D : Elements)
    D->print(OS);
  OS << '}';
}

void LValueType::print(raw_ostream &OS) const {
  OS << "[byref";

  Qual qs = getQualifiers();
  if (qs & (Qual::Implicit)) {
    OS << '(';
    if (qs & Qual::Implicit) OS << "implicit";
    OS << ')';
  }
  OS << "] ";
  getObjectType()->print(OS);
}
<|endoftext|>


<commit_before>
#include "Uniform.h"
#include "Utilities.h"

#include <ionMath.h>
#include <GL/glew.h>
#include <glm/gtc/type_ptr.hpp>

namespace ion
{
	namespace GL
	{
		template <>
		void Uniform::Bind<float>(uint const Handle, float const & Value)
		{
			CheckedGLCall(glUniform1f(Handle, Value));
		}

		template <>
		void Uniform::Bind<int>(uint const Handle, int const & Value)
		{
			CheckedGLCall(glUniform1i(Handle, Value));
		}

		template <>
		void Uniform::Bind<uint>(uint const Handle, uint const & Value)
		{
			CheckedGLCall(glUniform1i(Handle, Value));
		}

		template <>
		void Uniform::Bind<glm::mat4>(uint const Handle, glm::mat4 const & Value)
		{
			CheckedGLCall(glUniformMatrix4fv(Handle, 1, GL_FALSE, glm::value_ptr(Value)));
		}

		template <>
		void Uniform::Bind<vec2f>(uint const Handle, vec2f const & Value)
		{
			CheckedGLCall(glUniform2f(Handle, Value[0], Value[1]));
		}

		template <>
		void Uniform::Bind<vec3f>(uint const Handle, vec3f const & Value)
		{
			CheckedGLCall(glUniform3f(Handle, Value[0], Value[1], Value[2]));
		}

		template <>
		void Uniform::Bind<vec4f>(uint const Handle, vec4f const & Value)
		{
			CheckedGLCall(glUniform4f(Handle, Value[0], Value[1], Value[2], Value[3]));
		}

		template <>
		void Uniform::Bind<color3f>(uint const Handle, color3f const & Value)
		{
			CheckedGLCall(glUniform3f(Handle, Value[0], Value[1], Value[2]));
		}

		template <>
		void Uniform::Bind<color4f>(uint const Handle, color4f const & Value)
		{
			CheckedGLCall(glUniform4f(Handle, Value[0], Value[1], Value[2], Value[3]));
		}

		template <>
		void Uniform::Bind<vec2i>(uint const Handle, vec2i const & Value)
		{
			CheckedGLCall(glUniform2i(Handle, Value[0], Value[1]));
		}

		template <>
		void Uniform::Bind<vec3i>(uint const Handle, vec3i const & Value)
		{
			CheckedGLCall(glUniform3i(Handle, Value[0], Value[1], Value[2]));
		}

		template <>
		void Uniform::Bind<vec4i>(uint const Handle, vec4i const & Value)
		{
			CheckedGLCall(glUniform4i(Handle, Value[0], Value[1], Value[2], Value[3]));
		}

		template <>
		void Uniform::Bind<color3i>(uint const Handle, color3i const & Value)
		{
			CheckedGLCall(glUniform3i(Handle, Value[0], Value[1], Value[2]));
		}

		template <>
		void Uniform::Bind<color4i>(uint const Handle, color4i const & Value)
		{
			CheckedGLCall(glUniform4i(Handle, Value[0], Value[1], Value[2], Value[3]));
		}

		template <>
		void Uniform::Bind<vec2u>(uint const Handle, vec2u const & Value)
		{
			CheckedGLCall(glUniform2ui(Handle, Value[0], Value[1]));
		}

		template <>
		void Uniform::Bind<vec3u>(uint const Handle, vec3u const & Value)
		{
			CheckedGLCall(glUniform3ui(Handle, Value[0], Value[1], Value[2]));
		}

		template <>
		void Uniform::Bind<vec4u>(uint const Handle, vec4u const & Value)
		{
			CheckedGLCall(glUniform4ui(Handle, Value[0], Value[1], Value[2], Value[3]));
		}

		template <>
		void Uniform::Bind<bool>(uint const Handle, bool const & Value)
		{
			CheckedGLCall(glUniform1i(Handle, Value ? 1 : 0));
		}

		template <>
		void Uniform::Bind<vector<glm::mat4>>(uint const Handle, vector<glm::mat4> const & Value)
		{
			static vector<float> Temp;

			for (auto Mat : Value)
			{
				auto ValuePtr = glm::value_ptr(Mat);
				for (int i = 0; i < 16; ++ i)
					Temp.push_back(((float *) ValuePtr)[i]);
			}

			CheckedGLCall(glUniformMatrix4fv(Handle, (int) Value.size(), GL_FALSE, Temp.data()));
		}

		template <>
		void Uniform::Bind<vector<glm::mat4 *>>(uint const Handle, vector<glm::mat4 *> const & Value)
		{
			static vector<float> Temp;

			for (auto Mat : Value)
			{
				auto ValuePtr = glm::value_ptr(* Mat);
				for (int i = 0; i < 16; ++ i)
					Temp.push_back(((float *) ValuePtr)[i]);
			}

			CheckedGLCall(glUniformMatrix4fv(Handle, (int) Value.size(), GL_FALSE, Temp.data()));
		}
	}
}
<commit_msg>Fix issue with matrix array upload<commit_after>
#include "Uniform.h"
#include "Utilities.h"

#include <ionMath.h>
#include <GL/glew.h>
#include <glm/gtc/type_ptr.hpp>

namespace ion
{
	namespace GL
	{
		template <>
		void Uniform::Bind<float>(uint const Handle, float const & Value)
		{
			CheckedGLCall(glUniform1f(Handle, Value));
		}

		template <>
		void Uniform::Bind<int>(uint const Handle, int const & Value)
		{
			CheckedGLCall(glUniform1i(Handle, Value));
		}

		template <>
		void Uniform::Bind<uint>(uint const Handle, uint const & Value)
		{
			CheckedGLCall(glUniform1i(Handle, Value));
		}

		template <>
		void Uniform::Bind<glm::mat4>(uint const Handle, glm::mat4 const & Value)
		{
			CheckedGLCall(glUniformMatrix4fv(Handle, 1, GL_FALSE, glm::value_ptr(Value)));
		}

		template <>
		void Uniform::Bind<vec2f>(uint const Handle, vec2f const & Value)
		{
			CheckedGLCall(glUniform2f(Handle, Value[0], Value[1]));
		}

		template <>
		void Uniform::Bind<vec3f>(uint const Handle, vec3f const & Value)
		{
			CheckedGLCall(glUniform3f(Handle, Value[0], Value[1], Value[2]));
		}

		template <>
		void Uniform::Bind<vec4f>(uint const Handle, vec4f const & Value)
		{
			CheckedGLCall(glUniform4f(Handle, Value[0], Value[1], Value[2], Value[3]));
		}

		template <>
		void Uniform::Bind<color3f>(uint const Handle, color3f const & Value)
		{
			CheckedGLCall(glUniform3f(Handle, Value[0], Value[1], Value[2]));
		}

		template <>
		void Uniform::Bind<color4f>(uint const Handle, color4f const & Value)
		{
			CheckedGLCall(glUniform4f(Handle, Value[0], Value[1], Value[2], Value[3]));
		}

		template <>
		void Uniform::Bind<vec2i>(uint const Handle, vec2i const & Value)
		{
			CheckedGLCall(glUniform2i(Handle, Value[0], Value[1]));
		}

		template <>
		void Uniform::Bind<vec3i>(uint const Handle, vec3i const & Value)
		{
			CheckedGLCall(glUniform3i(Handle, Value[0], Value[1], Value[2]));
		}

		template <>
		void Uniform::Bind<vec4i>(uint const Handle, vec4i const & Value)
		{
			CheckedGLCall(glUniform4i(Handle, Value[0], Value[1], Value[2], Value[3]));
		}

		template <>
		void Uniform::Bind<color3i>(uint const Handle, color3i const & Value)
		{
			CheckedGLCall(glUniform3i(Handle, Value[0], Value[1], Value[2]));
		}

		template <>
		void Uniform::Bind<color4i>(uint const Handle, color4i const & Value)
		{
			CheckedGLCall(glUniform4i(Handle, Value[0], Value[1], Value[2], Value[3]));
		}

		template <>
		void Uniform::Bind<vec2u>(uint const Handle, vec2u const & Value)
		{
			CheckedGLCall(glUniform2ui(Handle, Value[0], Value[1]));
		}

		template <>
		void Uniform::Bind<vec3u>(uint const Handle, vec3u const & Value)
		{
			CheckedGLCall(glUniform3ui(Handle, Value[0], Value[1], Value[2]));
		}

		template <>
		void Uniform::Bind<vec4u>(uint const Handle, vec4u const & Value)
		{
			CheckedGLCall(glUniform4ui(Handle, Value[0], Value[1], Value[2], Value[3]));
		}

		template <>
		void Uniform::Bind<bool>(uint const Handle, bool const & Value)
		{
			CheckedGLCall(glUniform1i(Handle, Value ? 1 : 0));
		}

		template <>
		void Uniform::Bind<vector<glm::mat4>>(uint const Handle, vector<glm::mat4> const & Value)
		{
			static vector<float> Temp;

			for (auto Mat : Value)
			{
				auto ValuePtr = glm::value_ptr(Mat);
				for (int i = 0; i < 16; ++ i)
					Temp.push_back(((float *) ValuePtr)[i]);
			}

			CheckedGLCall(glUniformMatrix4fv(Handle, (int) Value.size(), GL_FALSE, Temp.data()));
			Temp.clear();
		}

		template <>
		void Uniform::Bind<vector<glm::mat4 *>>(uint const Handle, vector<glm::mat4 *> const & Value)
		{
			static vector<float> Temp;

			for (auto Mat : Value)
			{
				auto ValuePtr = glm::value_ptr(* Mat);
				for (int i = 0; i < 16; ++ i)
					Temp.push_back(((float *) ValuePtr)[i]);
			}

			CheckedGLCall(glUniformMatrix4fv(Handle, (int) Value.size(), GL_FALSE, Temp.data()));
			Temp.clear();
		}
	}
}
<|endoftext|>


<commit_before>#include "base/logging.h"
#include "gl_state.h"
#ifdef _WIN32
#include "GL/wglew.h"
#endif

#if defined(USING_GLES2)
#if defined(ANDROID)
PFNGLALPHAFUNCQCOMPROC glAlphaFuncQCOM;
PFNEGLGETSYSTEMTIMEFREQUENCYNVPROC eglGetSystemTimeFrequencyNV;
PFNEGLGETSYSTEMTIMENVPROC eglGetSystemTimeNV;
PFNGLMAPBUFFERPROC glMapBuffer;
#endif
#if !defined(IOS) && !defined(__SYMBIAN32__) && !defined(MEEGO_EDITION_HARMATTAN) && !defined(MAEMO)
PFNGLDISCARDFRAMEBUFFEREXTPROC glDiscardFramebufferEXT;
PFNGLGENVERTEXARRAYSOESPROC glGenVertexArraysOES;
PFNGLBINDVERTEXARRAYOESPROC glBindVertexArrayOES;
PFNGLDELETEVERTEXARRAYSOESPROC glDeleteVertexArraysOES;
PFNGLISVERTEXARRAYOESPROC glIsVertexArrayOES;
#endif
#endif

OpenGLState glstate;
GLExtensions gl_extensions;
std::string g_all_gl_extensions;
std::string g_all_egl_extensions;

int OpenGLState::state_count = 0;

void OpenGLState::Initialize() {
	if(initialized) return;

	Restore();

	initialized = true;
}

void OpenGLState::Restore() {
	int count = 0;
	blend.restore(); count++;
	blendEquation.restore(); count++;
	blendFuncSeparate.restore(); count++;
	blendColor.restore(); count++;

#if !defined(USING_GLES2)
	colorLogicOp.restore(); count++;
	logicOp.restore(); count++;
#endif

#ifdef ANDROID
	if (gl_extensions.QCOM_alpha_test) {
		alphaTestQCOM.restore(); count++;
		alphaFuncQCOM.restore(); count++;
	}
#endif

	scissorTest.restore(); count++;
	scissorRect.restore(); count++;

	cullFace.restore(); count++;
	cullFaceMode.restore(); count++;
	frontFace.restore(); count++;

	depthTest.restore(); count++;
	depthRange.restore(); count++;
	depthFunc.restore(); count++;
	depthWrite.restore(); count++;

	colorMask.restore(); count++;
	viewport.restore(); count++;

	stencilTest.restore(); count++;
	stencilOp.restore(); count++;
	stencilFunc.restore(); count++;

	dither.restore(); count++;

	if (count != state_count) {
		FLOG("OpenGLState::Restore is missing some states");
	}
}

// http://stackoverflow.com/questions/16147700/opengl-es-using-tegra-specific-extensions-gl-ext-texture-array

void CheckGLExtensions() {
	static bool done = false;
	if (done)
		return;
	done = true;

	memset(&gl_extensions, 0, sizeof(gl_extensions));

	const char *extString = (const char *)glGetString(GL_EXTENSIONS);
	if (extString) {
		g_all_gl_extensions = extString;
	} else {
		g_all_gl_extensions = "";
	}

#ifdef WIN32
	const char *wglString = wglGetExtensionsStringEXT();
	if (wglString) {
		gl_extensions.EXT_swap_control_tear = strstr(wglString, "WGL_EXT_swap_control_tear") != 0;
		g_all_egl_extensions = wglString;
	} else {
		g_all_egl_extensions = "";
	}
#elif !defined(USING_GLES2)
	// const char *glXString = glXQueryExtensionString();
	// gl_extensions.EXT_swap_control_tear = strstr(glXString, "GLX_EXT_swap_control_tear") != 0;
#endif

#ifdef USING_GLES2
	gl_extensions.OES_packed_depth_stencil = strstr(extString, "GL_OES_packed_depth_stencil") != 0;
	gl_extensions.OES_depth24 = strstr(extString, "GL_OES_depth24") != 0;
	gl_extensions.OES_depth_texture = strstr(extString, "GL_OES_depth_texture") != 0;
	gl_extensions.OES_mapbuffer = strstr(extString, "GL_OES_mapbuffer") != 0;
#if defined(IOS) || defined(__SYMBIAN32__) || defined(MEEGO_EDITION_HARMATTAN) || defined(MAEMO)
	gl_extensions.OES_vertex_array_object = false;
	gl_extensions.EXT_discard_framebuffer = false;
#else
	gl_extensions.OES_vertex_array_object = strstr(extString, "GL_OES_vertex_array_object") != 0;
	if (gl_extensions.OES_vertex_array_object) {
		glGenVertexArraysOES = (PFNGLGENVERTEXARRAYSOESPROC)eglGetProcAddress ( "glGenVertexArraysOES" );
		glBindVertexArrayOES = (PFNGLBINDVERTEXARRAYOESPROC)eglGetProcAddress ( "glBindVertexArrayOES" );
		glDeleteVertexArraysOES = (PFNGLDELETEVERTEXARRAYSOESPROC)eglGetProcAddress ( "glDeleteVertexArraysOES" );
		glIsVertexArrayOES = (PFNGLISVERTEXARRAYOESPROC)eglGetProcAddress ( "glIsVertexArrayOES" );
	}

	gl_extensions.EXT_discard_framebuffer = strstr(extString, "GL_EXT_discard_framebuffer") != 0;
	if (gl_extensions.EXT_discard_framebuffer) {
		glDiscardFramebufferEXT = (PFNGLDISCARDFRAMEBUFFEREXTPROC)eglGetProcAddress("glDiscardFramebufferEXT");
	}

#endif
#endif

#ifdef ANDROID
	if (gl_extensions.OES_mapbuffer) {
		glMapBuffer = (PFNGLMAPBUFFERPROC)eglGetProcAddress( "glMapBufferOES" );
	}

	gl_extensions.QCOM_alpha_test = strstr(extString, "GL_QCOM_alpha_test") != 0;
	// Load extensions that are not auto-loaded by Android.
	if (gl_extensions.QCOM_alpha_test) {
		glAlphaFuncQCOM = (PFNGLALPHAFUNCQCOMPROC)eglGetProcAddress("glAlphaFuncQCOM");
	}

	// Look for EGL extensions
	EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);

	const char *eglString = eglQueryString(display, EGL_EXTENSIONS);
	if (eglString) {
		g_all_egl_extensions = eglString;

		gl_extensions.EGL_NV_system_time = strstr(eglString, "EGL_NV_system_time") != 0;
		gl_extensions.EGL_NV_coverage_sample = strstr(eglString, "EGL_NV_coverage_sample") != 0;

		if (gl_extensions.EGL_NV_system_time) {
			eglGetSystemTimeNV = (PFNEGLGETSYSTEMTIMENVPROC) eglGetProcAddress("eglGetSystemTimeNV");
			eglGetSystemTimeFrequencyNV = (PFNEGLGETSYSTEMTIMEFREQUENCYNVPROC) eglGetProcAddress("eglGetSystemTimeFrequencyNV");
		}
	} else {
		g_all_egl_extensions = "";
	}

#endif

#ifdef USING_GLES2
	gl_extensions.FBO_ARB = true;
	gl_extensions.FBO_EXT = false;
#else
	gl_extensions.FBO_ARB = strstr(extString, "GL_ARB_framebuffer_object") != 0;
	gl_extensions.FBO_EXT = strstr(extString, "GL_EXT_framebuffer_object") != 0;
#endif
}

void OpenGLState::SetVSyncInterval(int interval) {
#ifdef _WIN32
	if( wglSwapIntervalEXT )
		wglSwapIntervalEXT(interval);
#endif
}
<commit_msg>Add gl_extensions.QCOM_binning_control<commit_after>#include "base/logging.h"
#include "gl_state.h"
#ifdef _WIN32
#include "GL/wglew.h"
#endif

#if defined(USING_GLES2)
#if defined(ANDROID)
PFNGLALPHAFUNCQCOMPROC glAlphaFuncQCOM;
PFNEGLGETSYSTEMTIMEFREQUENCYNVPROC eglGetSystemTimeFrequencyNV;
PFNEGLGETSYSTEMTIMENVPROC eglGetSystemTimeNV;
PFNGLMAPBUFFERPROC glMapBuffer;
#endif
#if !defined(IOS) && !defined(__SYMBIAN32__) && !defined(MEEGO_EDITION_HARMATTAN) && !defined(MAEMO)
PFNGLDISCARDFRAMEBUFFEREXTPROC glDiscardFramebufferEXT;
PFNGLGENVERTEXARRAYSOESPROC glGenVertexArraysOES;
PFNGLBINDVERTEXARRAYOESPROC glBindVertexArrayOES;
PFNGLDELETEVERTEXARRAYSOESPROC glDeleteVertexArraysOES;
PFNGLISVERTEXARRAYOESPROC glIsVertexArrayOES;
#endif
#endif

OpenGLState glstate;
GLExtensions gl_extensions;
std::string g_all_gl_extensions;
std::string g_all_egl_extensions;

int OpenGLState::state_count = 0;

void OpenGLState::Initialize() {
	if(initialized) return;

	Restore();

	initialized = true;
}

void OpenGLState::Restore() {
	int count = 0;
	blend.restore(); count++;
	blendEquation.restore(); count++;
	blendFuncSeparate.restore(); count++;
	blendColor.restore(); count++;

#if !defined(USING_GLES2)
	colorLogicOp.restore(); count++;
	logicOp.restore(); count++;
#endif

#ifdef ANDROID
	if (gl_extensions.QCOM_alpha_test) {
		alphaTestQCOM.restore(); count++;
		alphaFuncQCOM.restore(); count++;
	}
#endif

	scissorTest.restore(); count++;
	scissorRect.restore(); count++;

	cullFace.restore(); count++;
	cullFaceMode.restore(); count++;
	frontFace.restore(); count++;

	depthTest.restore(); count++;
	depthRange.restore(); count++;
	depthFunc.restore(); count++;
	depthWrite.restore(); count++;

	colorMask.restore(); count++;
	viewport.restore(); count++;

	stencilTest.restore(); count++;
	stencilOp.restore(); count++;
	stencilFunc.restore(); count++;

	dither.restore(); count++;

	if (count != state_count) {
		FLOG("OpenGLState::Restore is missing some states");
	}
}

// http://stackoverflow.com/questions/16147700/opengl-es-using-tegra-specific-extensions-gl-ext-texture-array

void CheckGLExtensions() {
	static bool done = false;
	if (done)
		return;
	done = true;

	memset(&gl_extensions, 0, sizeof(gl_extensions));

	const char *extString = (const char *)glGetString(GL_EXTENSIONS);
	if (extString) {
		g_all_gl_extensions = extString;
	} else {
		g_all_gl_extensions = "";
	}

#ifdef WIN32
	const char *wglString = wglGetExtensionsStringEXT();
	if (wglString) {
		gl_extensions.EXT_swap_control_tear = strstr(wglString, "WGL_EXT_swap_control_tear") != 0;
		g_all_egl_extensions = wglString;
	} else {
		g_all_egl_extensions = "";
	}
#elif !defined(USING_GLES2)
	// const char *glXString = glXQueryExtensionString();
	// gl_extensions.EXT_swap_control_tear = strstr(glXString, "GLX_EXT_swap_control_tear") != 0;
#endif

#ifdef USING_GLES2
	gl_extensions.OES_packed_depth_stencil = strstr(extString, "GL_OES_packed_depth_stencil") != 0;
	gl_extensions.OES_depth24 = strstr(extString, "GL_OES_depth24") != 0;
	gl_extensions.OES_depth_texture = strstr(extString, "GL_OES_depth_texture") != 0;
	gl_extensions.OES_mapbuffer = strstr(extString, "GL_OES_mapbuffer") != 0;
#if defined(IOS) || defined(__SYMBIAN32__) || defined(MEEGO_EDITION_HARMATTAN) || defined(MAEMO)
	gl_extensions.OES_vertex_array_object = false;
	gl_extensions.EXT_discard_framebuffer = false;
#else
	gl_extensions.OES_vertex_array_object = strstr(extString, "GL_OES_vertex_array_object") != 0;
	if (gl_extensions.OES_vertex_array_object) {
		glGenVertexArraysOES = (PFNGLGENVERTEXARRAYSOESPROC)eglGetProcAddress ( "glGenVertexArraysOES" );
		glBindVertexArrayOES = (PFNGLBINDVERTEXARRAYOESPROC)eglGetProcAddress ( "glBindVertexArrayOES" );
		glDeleteVertexArraysOES = (PFNGLDELETEVERTEXARRAYSOESPROC)eglGetProcAddress ( "glDeleteVertexArraysOES" );
		glIsVertexArrayOES = (PFNGLISVERTEXARRAYOESPROC)eglGetProcAddress ( "glIsVertexArrayOES" );
	}

	gl_extensions.EXT_discard_framebuffer = strstr(extString, "GL_EXT_discard_framebuffer") != 0;
	if (gl_extensions.EXT_discard_framebuffer) {
		glDiscardFramebufferEXT = (PFNGLDISCARDFRAMEBUFFEREXTPROC)eglGetProcAddress("glDiscardFramebufferEXT");
	}

#endif
#endif

#ifdef ANDROID
	if (gl_extensions.OES_mapbuffer) {
		glMapBuffer = (PFNGLMAPBUFFERPROC)eglGetProcAddress( "glMapBufferOES" );
	}
	gl_extensions.QCOM_binning_control = strstr(extString, "GL_QCOM_binning_control") != 0;
	gl_extensions.QCOM_alpha_test = strstr(extString, "GL_QCOM_alpha_test") != 0;
	// Load extensions that are not auto-loaded by Android.
	if (gl_extensions.QCOM_alpha_test) {
		glAlphaFuncQCOM = (PFNGLALPHAFUNCQCOMPROC)eglGetProcAddress("glAlphaFuncQCOM");
	}

	// Look for EGL extensions
	EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);

	const char *eglString = eglQueryString(display, EGL_EXTENSIONS);
	if (eglString) {
		g_all_egl_extensions = eglString;

		gl_extensions.EGL_NV_system_time = strstr(eglString, "EGL_NV_system_time") != 0;
		gl_extensions.EGL_NV_coverage_sample = strstr(eglString, "EGL_NV_coverage_sample") != 0;

		if (gl_extensions.EGL_NV_system_time) {
			eglGetSystemTimeNV = (PFNEGLGETSYSTEMTIMENVPROC) eglGetProcAddress("eglGetSystemTimeNV");
			eglGetSystemTimeFrequencyNV = (PFNEGLGETSYSTEMTIMEFREQUENCYNVPROC) eglGetProcAddress("eglGetSystemTimeFrequencyNV");
		}
	} else {
		g_all_egl_extensions = "";
	}

#endif

#ifdef USING_GLES2
	gl_extensions.FBO_ARB = true;
	gl_extensions.FBO_EXT = false;
#else
	gl_extensions.FBO_ARB = strstr(extString, "GL_ARB_framebuffer_object") != 0;
	gl_extensions.FBO_EXT = strstr(extString, "GL_EXT_framebuffer_object") != 0;
#endif
}

void OpenGLState::SetVSyncInterval(int interval) {
#ifdef _WIN32
	if( wglSwapIntervalEXT )
		wglSwapIntervalEXT(interval);
#endif
}
<|endoftext|>


<commit_before>/* Copyright 2017 The TensorFlow Authors. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
#include <string>
#include <utility>

#include "tensorflow/core/data/dataset_utils.h"
#include "tensorflow/core/framework/dataset.h"
#include "tensorflow/core/framework/partial_tensor_shape.h"
#include "tensorflow/core/framework/tensor.h"
#include "tensorflow/core/framework/tensor_util.h"
#include "tensorflow/core/util/batch_util.h"

namespace tensorflow {
namespace data {
namespace experimental {
namespace {

class UnbatchDatasetOp : public UnaryDatasetOpKernel {
 public:
  explicit UnbatchDatasetOp(OpKernelConstruction* ctx)
      : UnaryDatasetOpKernel(ctx) {}

  void MakeDataset(OpKernelContext* ctx, DatasetBase* input,
                   DatasetBase** output) override {
    *output = new Dataset(ctx, input);
  }

 private:
  class Dataset : public DatasetBase {
   public:
    explicit Dataset(OpKernelContext* ctx, DatasetBase* input)
        : DatasetBase(DatasetContext(ctx)), input_(input) {
      input_->Ref();
      batch_size_ = -1;
      for (const PartialTensorShape& shape : input->output_shapes()) {
        if (!shape.unknown_rank()) {
          if (batch_size_ < 0 && shape.dim_size(0) >= 0) {
            batch_size_ = shape.dim_size(0);
          }
          gtl::InlinedVector<int64_t, 4> partial_dim_sizes;
          for (int i = 1; i < shape.dims(); ++i) {
            partial_dim_sizes.push_back(shape.dim_size(i));
          }
          shapes_.emplace_back(std::move(partial_dim_sizes));
        } else {
          // If the input shape is unknown, the output shape will be unknown.
          shapes_.emplace_back();
        }
      }
    }

    ~Dataset() override { input_->Unref(); }

    std::unique_ptr<IteratorBase> MakeIteratorInternal(
        const string& prefix) const override {
      return absl::make_unique<Iterator>(
          Iterator::Params{this, strings::StrCat(prefix, "::Unbatch")});
    }

    const DataTypeVector& output_dtypes() const override {
      return input_->output_dtypes();
    }
    const std::vector<PartialTensorShape>& output_shapes() const override {
      return shapes_;
    }

    string DebugString() const override { return "UnbatchDatasetOp::Dataset"; }

    int64_t Cardinality() const override {
      int64_t n = input_->Cardinality();
      if (n == kInfiniteCardinality || n == kUnknownCardinality) {
        return n;
      }
      if (batch_size_ > 0) {
        return n * batch_size_;
      }
      return kUnknownCardinality;
    }

    Status InputDatasets(
        std::vector<const DatasetBase*>* inputs) const override {
      inputs->push_back(input_);
      return Status::OK();
    }

    Status CheckExternalState() const override {
      return input_->CheckExternalState();
    }

   protected:
    Status AsGraphDefInternal(SerializationContext* ctx,
                              DatasetGraphDefBuilder* b,
                              Node** output) const override {
      Node* input_graph_node = nullptr;
      TF_RETURN_IF_ERROR(b->AddInputDataset(ctx, input_, &input_graph_node));
      TF_RETURN_IF_ERROR(b->AddDataset(this, {input_graph_node}, output));
      return Status::OK();
    }

   private:
    class Iterator : public DatasetIterator<Dataset> {
     public:
      explicit Iterator(const Params& params)
          : DatasetIterator<Dataset>(params),
            current_index_(0),
            current_batch_size_(0),
            shapes_(params.dataset->output_shapes().size()) {}

      Status Initialize(IteratorContext* ctx) override {
        return dataset()->input_->MakeIterator(ctx, this, prefix(),
                                               &input_impl_);
      }

      Status GetNextInternal(IteratorContext* ctx,
                             std::vector<Tensor>* out_tensors,
                             bool* end_of_sequence) override {
        mutex_lock l(mu_);
        if (!input_impl_) {
          *end_of_sequence = true;
          return Status::OK();
        }
        *end_of_sequence = false;
        while (!*end_of_sequence) {
          if (current_index_ < current_batch_size_) {
            out_tensors->clear();
            out_tensors->reserve(tensors_.size());
            for (int i = 0; i < tensors_.size(); ++i) {
              out_tensors->push_back(
                  MaybeCopySubSlice(tensors_[i], current_index_));
            }
            ++current_index_;
            *end_of_sequence = false;
            return Status::OK();
          }
          current_index_ = 0;
          current_batch_size_ = 0;
          tensors_.clear();
          TF_RETURN_IF_ERROR(
              input_impl_->GetNext(ctx, &tensors_, end_of_sequence));
          if (!*end_of_sequence) {
            for (size_t i = 0; i < tensors_.size(); ++i) {
              if (tensors_[i].dims() == 0) {
                return errors::InvalidArgument(
                    "Input element must have a non-scalar value in each "
                    "component.");
              }
              if (tensors_[i].dim_size(0) != tensors_[0].dim_size(0)) {
                return errors::InvalidArgument(
                    "Input element must have the same batch size in each "
                    "component. Component 0 had size ",
                    tensors_[0].dim_size(0), " but component ", i,
                    " had size, ", tensors_[i].dim_size(0), ".");
              }
              shapes_[i] = tensors_[i].shape();
              shapes_[i].RemoveDim(0);
            }
            current_batch_size_ = tensors_[0].dim_size(0);
          }
        }
        input_impl_.reset();
        return Status::OK();
      }

     protected:
      std::shared_ptr<model::Node> CreateNode(
          IteratorContext* ctx, model::Node::Args args) const override {
        // Unbatch assumes that all input components have the same leading
        // dimension. If it is statically known for any component, we model the
        // transformation using `KnownRatio`. Otherwise, we use `UnknownRatio`.
        for (auto& shape : dataset()->input_->output_shapes()) {
          if (shape.dims() > 0 && shape.dim_size(0) > 0) {
            return model::MakeKnownRatioNode(
                std::move(args), 1.0 / static_cast<double>(shape.dim_size(0)));
          }
        }
        return model::MakeUnknownRatioNode(std::move(args));
      }

      Status SaveInternal(SerializationContext* ctx,
                          IteratorStateWriter* writer) override {
        mutex_lock l(mu_);
        if (input_impl_) {
          TF_RETURN_IF_ERROR(SaveInput(ctx, writer, input_impl_));
        } else {
          TF_RETURN_IF_ERROR(
              writer->WriteScalar(full_name("input_impl_empty"), ""));
        }
        TF_RETURN_IF_ERROR(
            writer->WriteScalar(full_name("current_index"), current_index_));
        TF_RETURN_IF_ERROR(
            writer->WriteScalar(full_name("n"), current_batch_size_));
        if (current_index_ < current_batch_size_) {
          for (size_t i = 0; i < tensors_.size(); ++i) {
            TF_RETURN_IF_ERROR(writer->WriteTensor(
                full_name(strings::StrCat("tensors[", i, "]")), tensors_[i]));
          }
        }
        return Status::OK();
      }

      Status RestoreInternal(IteratorContext* ctx,
                             IteratorStateReader* reader) override {
        mutex_lock l(mu_);
        if (!reader->Contains(full_name("input_impl_empty"))) {
          TF_RETURN_IF_ERROR(RestoreInput(ctx, reader, input_impl_));
        } else {
          input_impl_.reset();
        }
        TF_RETURN_IF_ERROR(
            reader->ReadScalar(full_name("current_index"), &current_index_));
        TF_RETURN_IF_ERROR(
            reader->ReadScalar(full_name("n"), &current_batch_size_));
        tensors_.clear();
        tensors_.resize(dataset()->output_dtypes().size());
        if (current_index_ < current_batch_size_) {
          for (size_t i = 0; i < tensors_.size(); ++i) {
            TF_RETURN_IF_ERROR(reader->ReadTensor(
                ctx->flr(), full_name(strings::StrCat("tensors[", i, "]")),
                &tensors_[i]));
            shapes_[i] = tensors_[i].shape();
            shapes_[i].RemoveDim(0);
          }
        }
        return Status::OK();
      }

     private:
      mutex mu_;
      int64_t current_index_ TF_GUARDED_BY(mu_);
      int64_t current_batch_size_ TF_GUARDED_BY(mu_);
      std::vector<Tensor> tensors_ TF_GUARDED_BY(mu_);
      std::unique_ptr<IteratorBase> input_impl_ TF_GUARDED_BY(mu_);
      std::vector<TensorShape> shapes_ TF_GUARDED_BY(mu_);
    };

    const DatasetBase* const input_;
    std::vector<PartialTensorShape> shapes_;
    // batch_size_ may or may not be known, with -1 as unknown
    int64_t batch_size_;
  };
};

REGISTER_KERNEL_BUILDER(Name("UnbatchDataset").Device(DEVICE_CPU),
                        UnbatchDatasetOp);
REGISTER_KERNEL_BUILDER(Name("ExperimentalUnbatchDataset").Device(DEVICE_CPU),
                        UnbatchDatasetOp);

}  // namespace
}  // namespace experimental
}  // namespace data
}  // namespace tensorflow
<commit_msg>Undo cl/380581935 in unbatch() to fix memory leak<commit_after>/* Copyright 2017 The TensorFlow Authors. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
#include <string>
#include <utility>

#include "tensorflow/core/data/dataset_utils.h"
#include "tensorflow/core/framework/dataset.h"
#include "tensorflow/core/framework/partial_tensor_shape.h"
#include "tensorflow/core/framework/tensor.h"
#include "tensorflow/core/framework/tensor_util.h"
#include "tensorflow/core/util/batch_util.h"

namespace tensorflow {
namespace data {
namespace experimental {
namespace {

class UnbatchDatasetOp : public UnaryDatasetOpKernel {
 public:
  explicit UnbatchDatasetOp(OpKernelConstruction* ctx)
      : UnaryDatasetOpKernel(ctx) {}

  void MakeDataset(OpKernelContext* ctx, DatasetBase* input,
                   DatasetBase** output) override {
    *output = new Dataset(ctx, input);
  }

 private:
  class Dataset : public DatasetBase {
   public:
    explicit Dataset(OpKernelContext* ctx, DatasetBase* input)
        : DatasetBase(DatasetContext(ctx)), input_(input) {
      input_->Ref();
      batch_size_ = -1;
      for (const PartialTensorShape& shape : input->output_shapes()) {
        if (!shape.unknown_rank()) {
          if (batch_size_ < 0 && shape.dim_size(0) >= 0) {
            batch_size_ = shape.dim_size(0);
          }
          gtl::InlinedVector<int64_t, 4> partial_dim_sizes;
          for (int i = 1; i < shape.dims(); ++i) {
            partial_dim_sizes.push_back(shape.dim_size(i));
          }
          shapes_.emplace_back(std::move(partial_dim_sizes));
        } else {
          // If the input shape is unknown, the output shape will be unknown.
          shapes_.emplace_back();
        }
      }
    }

    ~Dataset() override { input_->Unref(); }

    std::unique_ptr<IteratorBase> MakeIteratorInternal(
        const string& prefix) const override {
      return absl::make_unique<Iterator>(
          Iterator::Params{this, strings::StrCat(prefix, "::Unbatch")});
    }

    const DataTypeVector& output_dtypes() const override {
      return input_->output_dtypes();
    }
    const std::vector<PartialTensorShape>& output_shapes() const override {
      return shapes_;
    }

    string DebugString() const override { return "UnbatchDatasetOp::Dataset"; }

    int64_t Cardinality() const override {
      int64_t n = input_->Cardinality();
      if (n == kInfiniteCardinality || n == kUnknownCardinality) {
        return n;
      }
      if (batch_size_ > 0) {
        return n * batch_size_;
      }
      return kUnknownCardinality;
    }

    Status InputDatasets(
        std::vector<const DatasetBase*>* inputs) const override {
      inputs->push_back(input_);
      return Status::OK();
    }

    Status CheckExternalState() const override {
      return input_->CheckExternalState();
    }

   protected:
    Status AsGraphDefInternal(SerializationContext* ctx,
                              DatasetGraphDefBuilder* b,
                              Node** output) const override {
      Node* input_graph_node = nullptr;
      TF_RETURN_IF_ERROR(b->AddInputDataset(ctx, input_, &input_graph_node));
      TF_RETURN_IF_ERROR(b->AddDataset(this, {input_graph_node}, output));
      return Status::OK();
    }

   private:
    class Iterator : public DatasetIterator<Dataset> {
     public:
      explicit Iterator(const Params& params)
          : DatasetIterator<Dataset>(params),
            current_index_(0),
            current_batch_size_(0),
            shapes_(params.dataset->output_shapes().size()) {}

      Status Initialize(IteratorContext* ctx) override {
        return dataset()->input_->MakeIterator(ctx, this, prefix(),
                                               &input_impl_);
      }

      Status GetNextInternal(IteratorContext* ctx,
                             std::vector<Tensor>* out_tensors,
                             bool* end_of_sequence) override {
        mutex_lock l(mu_);
        if (!input_impl_) {
          *end_of_sequence = true;
          return Status::OK();
        }
        *end_of_sequence = false;
        while (!*end_of_sequence) {
          if (current_index_ < current_batch_size_) {
            out_tensors->clear();
            out_tensors->reserve(tensors_.size());
            for (int i = 0; i < tensors_.size(); ++i) {
              // TODO(b/201790899): Investigate why using MaybeCopySubSlice
              // may lead to a memory leak.
              out_tensors->emplace_back(ctx->allocator({}), tensors_[i].dtype(),
                                        shapes_[i]);
              TF_RETURN_IF_ERROR(batch_util::MaybeMoveSliceToElement(
                  &tensors_[i], &out_tensors->back(), current_index_));
            }
            ++current_index_;
            *end_of_sequence = false;
            return Status::OK();
          }
          current_index_ = 0;
          current_batch_size_ = 0;
          tensors_.clear();
          TF_RETURN_IF_ERROR(
              input_impl_->GetNext(ctx, &tensors_, end_of_sequence));
          if (!*end_of_sequence) {
            for (size_t i = 0; i < tensors_.size(); ++i) {
              if (tensors_[i].dims() == 0) {
                return errors::InvalidArgument(
                    "Input element must have a non-scalar value in each "
                    "component.");
              }
              if (tensors_[i].dim_size(0) != tensors_[0].dim_size(0)) {
                return errors::InvalidArgument(
                    "Input element must have the same batch size in each "
                    "component. Component 0 had size ",
                    tensors_[0].dim_size(0), " but component ", i,
                    " had size, ", tensors_[i].dim_size(0), ".");
              }
              shapes_[i] = tensors_[i].shape();
              shapes_[i].RemoveDim(0);
            }
            current_batch_size_ = tensors_[0].dim_size(0);
          }
        }
        input_impl_.reset();
        return Status::OK();
      }

     protected:
      std::shared_ptr<model::Node> CreateNode(
          IteratorContext* ctx, model::Node::Args args) const override {
        // Unbatch assumes that all input components have the same leading
        // dimension. If it is statically known for any component, we model the
        // transformation using `KnownRatio`. Otherwise, we use `UnknownRatio`.
        for (auto& shape : dataset()->input_->output_shapes()) {
          if (shape.dims() > 0 && shape.dim_size(0) > 0) {
            return model::MakeKnownRatioNode(
                std::move(args), 1.0 / static_cast<double>(shape.dim_size(0)));
          }
        }
        return model::MakeUnknownRatioNode(std::move(args));
      }

      Status SaveInternal(SerializationContext* ctx,
                          IteratorStateWriter* writer) override {
        mutex_lock l(mu_);
        if (input_impl_) {
          TF_RETURN_IF_ERROR(SaveInput(ctx, writer, input_impl_));
        } else {
          TF_RETURN_IF_ERROR(
              writer->WriteScalar(full_name("input_impl_empty"), ""));
        }
        TF_RETURN_IF_ERROR(
            writer->WriteScalar(full_name("current_index"), current_index_));
        TF_RETURN_IF_ERROR(
            writer->WriteScalar(full_name("n"), current_batch_size_));
        if (current_index_ < current_batch_size_) {
          for (size_t i = 0; i < tensors_.size(); ++i) {
            TF_RETURN_IF_ERROR(writer->WriteTensor(
                full_name(strings::StrCat("tensors[", i, "]")), tensors_[i]));
          }
        }
        return Status::OK();
      }

      Status RestoreInternal(IteratorContext* ctx,
                             IteratorStateReader* reader) override {
        mutex_lock l(mu_);
        if (!reader->Contains(full_name("input_impl_empty"))) {
          TF_RETURN_IF_ERROR(RestoreInput(ctx, reader, input_impl_));
        } else {
          input_impl_.reset();
        }
        TF_RETURN_IF_ERROR(
            reader->ReadScalar(full_name("current_index"), &current_index_));
        TF_RETURN_IF_ERROR(
            reader->ReadScalar(full_name("n"), &current_batch_size_));
        tensors_.clear();
        tensors_.resize(dataset()->output_dtypes().size());
        if (current_index_ < current_batch_size_) {
          for (size_t i = 0; i < tensors_.size(); ++i) {
            TF_RETURN_IF_ERROR(reader->ReadTensor(
                ctx->flr(), full_name(strings::StrCat("tensors[", i, "]")),
                &tensors_[i]));
            shapes_[i] = tensors_[i].shape();
            shapes_[i].RemoveDim(0);
          }
        }
        return Status::OK();
      }

     private:
      mutex mu_;
      int64_t current_index_ TF_GUARDED_BY(mu_);
      int64_t current_batch_size_ TF_GUARDED_BY(mu_);
      std::vector<Tensor> tensors_ TF_GUARDED_BY(mu_);
      std::unique_ptr<IteratorBase> input_impl_ TF_GUARDED_BY(mu_);
      std::vector<TensorShape> shapes_ TF_GUARDED_BY(mu_);
    };

    const DatasetBase* const input_;
    std::vector<PartialTensorShape> shapes_;
    // batch_size_ may or may not be known, with -1 as unknown
    int64_t batch_size_;
  };
};

REGISTER_KERNEL_BUILDER(Name("UnbatchDataset").Device(DEVICE_CPU),
                        UnbatchDatasetOp);
REGISTER_KERNEL_BUILDER(Name("ExperimentalUnbatchDataset").Device(DEVICE_CPU),
                        UnbatchDatasetOp);

}  // namespace
}  // namespace experimental
}  // namespace data
}  // namespace tensorflow
<|endoftext|>


<commit_before>/* Copyright 2021 The TensorFlow Authors. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/

#include "tensorflow_lite_support/cc/task/processor/image_preprocessor.h"

#include "tensorflow_lite_support/cc/port/status_macros.h"
#include "tensorflow_lite_support/cc/task/core/task_utils.h"
#include "tensorflow_lite_support/cc/task/vision/proto/bounding_box_proto_inc.h"
#include "tensorflow_lite_support/cc/task/vision/utils/frame_buffer_utils.h"
#include "tensorflow_lite_support/cc/task/vision/utils/image_tensor_specs.h"

namespace tflite {
namespace task {
namespace processor {

namespace {
// Number of bytes required for 8-bit per pixel RGB color space.
static constexpr int kRgbPixelBytes = 3;

using ::tflite::task::vision::BoundingBox;
using ::tflite::task::vision::FrameBuffer;
}  // namespace

// Returns false if image preprocessing could be skipped, true otherwise.
bool ImagePreprocessor::IsImagePreprocessingNeeded(
    const FrameBuffer& frame_buffer, const BoundingBox& roi) {
  // Is crop required?
  if (roi.origin_x() != 0 || roi.origin_y() != 0 ||
      roi.width() != frame_buffer.dimension().width ||
      roi.height() != frame_buffer.dimension().height) {
    return true;
  }

  // Are image transformations required?
  if (frame_buffer.orientation() != FrameBuffer::Orientation::kTopLeft ||
      frame_buffer.format() != FrameBuffer::Format::kRGB ||
      frame_buffer.dimension().width != input_specs_.image_width ||
      frame_buffer.dimension().height != input_specs_.image_height) {
    return true;
  }

  return false;
}

absl::Status ImagePreprocessor::Init(
    const vision::FrameBufferUtils::ProcessEngine& process_engine) {
  frame_buffer_utils_ = vision::FrameBufferUtils::Create(process_engine);

  ASSIGN_OR_RETURN(input_specs_, vision::BuildInputImageTensorSpecs(
                                     *engine_->interpreter(),
                                     *engine_->metadata_extractor()));

  if (input_specs_.color_space != tflite::ColorSpaceType_RGB) {
    return tflite::support::CreateStatusWithPayload(
        absl::StatusCode::kUnimplemented,
        "ImagePreprocessor only supports RGB color space for now.");
  }

  return absl::OkStatus();
}

absl::Status ImagePreprocessor::Preprocess(const FrameBuffer& frame_buffer) {
  BoundingBox roi;
  roi.set_width(frame_buffer.dimension().width);
  roi.set_height(frame_buffer.dimension().height);
  return Preprocess(frame_buffer, roi);
}

absl::Status ImagePreprocessor::Preprocess(const FrameBuffer& frame_buffer,
                                           const BoundingBox& roi) {
  // Input data to be normalized (if needed) and used for inference. In most
  // cases, this is the result of image preprocessing. In case no image
  // preprocessing is needed (see below), this points to the input frame
  // buffer raw data.
  const uint8* input_data;
  size_t input_data_byte_size;

  // Optional buffers in case image preprocessing is needed.
  std::unique_ptr<FrameBuffer> preprocessed_frame_buffer;
  std::vector<uint8> preprocessed_data;

  if (IsImagePreprocessingNeeded(frame_buffer, roi)) {
    // Preprocess input image to fit model requirements.
    // For now RGB is the only color space supported, which is ensured by
    // `InitInternal`.
    FrameBuffer::Dimension to_buffer_dimension = {input_specs_.image_width,
                                                  input_specs_.image_height};
    input_data_byte_size =
        GetBufferByteSize(to_buffer_dimension, FrameBuffer::Format::kRGB);
    preprocessed_data.resize(input_data_byte_size / sizeof(uint8), 0);
    input_data = preprocessed_data.data();

    FrameBuffer::Plane preprocessed_plane = {
        /*buffer=*/preprocessed_data.data(),
        /*stride=*/{input_specs_.image_width * kRgbPixelBytes, kRgbPixelBytes}};
    preprocessed_frame_buffer = FrameBuffer::Create(
        {preprocessed_plane}, to_buffer_dimension, FrameBuffer::Format::kRGB,
        FrameBuffer::Orientation::kTopLeft);

    RETURN_IF_ERROR(frame_buffer_utils_->Preprocess(
        frame_buffer, roi, preprocessed_frame_buffer.get()));
  } else {
    // Input frame buffer already targets model requirements: skip image
    // preprocessing. For RGB, the data is always stored in a single plane.
    input_data = frame_buffer.plane(0).buffer;
    input_data_byte_size = frame_buffer.plane(0).stride.row_stride_bytes *
                           frame_buffer.dimension().height;
  }

  // Then normalize pixel data (if needed) and populate the input tensor.
  switch (input_specs_.tensor_type) {
    case kTfLiteUInt8:
      if (Tensor()->bytes != input_data_byte_size) {
        return tflite::support::CreateStatusWithPayload(
            absl::StatusCode::kInternal,
            "Size mismatch or unsupported padding bytes between pixel data "
            "and input tensor.");
      }
      // No normalization required: directly populate data.
      tflite::task::core::PopulateTensor(
          input_data, input_data_byte_size / sizeof(uint8), Tensor());
      break;
    case kTfLiteFloat32: {
      if (Tensor()->bytes / sizeof(float) !=
          input_data_byte_size / sizeof(uint8)) {
        return tflite::support::CreateStatusWithPayload(
            absl::StatusCode::kInternal,
            "Size mismatch or unsupported padding bytes between pixel data "
            "and input tensor.");
      }
      // Normalize and populate.
      float* normalized_input_data =
          tflite::task::core::AssertAndReturnTypedTensor<float>(Tensor());
      const tflite::task::vision::NormalizationOptions& normalization_options =
          input_specs_.normalization_options.value();
      for (int i = 0; i < normalization_options.num_values; i++) {
        if (std::abs(normalization_options.std_values[i]) <
            std::numeric_limits<float>::epsilon()) {
          return tflite::support::CreateStatusWithPayload(
              absl::StatusCode::kInternal,
              "NormalizationOptions.std_values can't be 0. Please check if the "
              "tensor metadata has been populated correctly.");
        }
      }
      if (normalization_options.num_values == 1) {
        float mean_value = normalization_options.mean_values[0];
        float inv_std_value = (1.0f / normalization_options.std_values[0]);
        for (size_t i = 0; i < input_data_byte_size / sizeof(uint8);
             i++, input_data++, normalized_input_data++) {
          *normalized_input_data =
              inv_std_value * (static_cast<float>(*input_data) - mean_value);
        }
      } else {
        std::array<float, 3> inv_std_values = {
            1.0f / normalization_options.std_values[0],
            1.0f / normalization_options.std_values[1],
            1.0f / normalization_options.std_values[2]};
        for (size_t i = 0; i < input_data_byte_size / sizeof(uint8);
             i++, input_data++, normalized_input_data++) {
          *normalized_input_data = inv_std_values[i % 3] *
                                   (static_cast<float>(*input_data) -
                                    normalization_options.mean_values[i % 3]);
        }
      }
      break;
    }
    case kTfLiteInt8:
      return tflite::support::CreateStatusWithPayload(
          absl::StatusCode::kUnimplemented,
          "kTfLiteInt8 input type is not implemented yet.");
    default:
      return tflite::support::CreateStatusWithPayload(
          absl::StatusCode::kInternal, "Unexpected input tensor type.");
  }

  return absl::OkStatus();
}

}  // namespace processor
}  // namespace task
}  // namespace tflite
<commit_msg>Resize graph inside Preprocess().<commit_after>/* Copyright 2021 The TensorFlow Authors. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/

#include "tensorflow_lite_support/cc/task/processor/image_preprocessor.h"

#include "tensorflow_lite_support/cc/port/status_macros.h"
#include "tensorflow_lite_support/cc/task/core/task_utils.h"
#include "tensorflow_lite_support/cc/task/vision/proto/bounding_box_proto_inc.h"
#include "tensorflow_lite_support/cc/task/vision/utils/frame_buffer_utils.h"
#include "tensorflow_lite_support/cc/task/vision/utils/image_tensor_specs.h"

namespace tflite {
namespace task {
namespace processor {

namespace {
// Number of bytes required for 8-bit per pixel RGB color space.
static constexpr int kRgbPixelBytes = 3;

using ::tflite::task::vision::BoundingBox;
using ::tflite::task::vision::FrameBuffer;
}  // namespace

// Returns false if image preprocessing could be skipped, true otherwise.
bool ImagePreprocessor::IsImagePreprocessingNeeded(
    const FrameBuffer& frame_buffer, const BoundingBox& roi) {
  // Is crop required?
  if (roi.origin_x() != 0 || roi.origin_y() != 0 ||
      roi.width() != frame_buffer.dimension().width ||
      roi.height() != frame_buffer.dimension().height) {
    return true;
  }

  // Are image transformations required?
  if (frame_buffer.orientation() != FrameBuffer::Orientation::kTopLeft ||
      frame_buffer.format() != FrameBuffer::Format::kRGB ||
      frame_buffer.dimension().width != input_specs_.image_width ||
      frame_buffer.dimension().height != input_specs_.image_height) {
    return true;
  }

  return false;
}

// Returns true if the model expects dynamic image shape, false otherwise.
bool ImagePreprocessor::IsInputImageDynamic()
{
  // Determine if the input shape is resizable.
  const TfLiteIntArray* dims_signature = Tensor()->dims_signature;

  if (dims_signature == nullptr) return false;

  bool height_or_width_mutable = dims_signature->data[1] == -1 ||
                                 dims_signature->data[2] == -1;
  // Only the HXW dimensions support mutability.
  bool batch_and_color_fixed = dims_signature->data[0] != -1 &&
                               dims_signature->data[3] != -1;

  if (height_or_width_mutable && batch_and_color_fixed) return true;

  return false;
}

absl::Status ImagePreprocessor::Init(
    const vision::FrameBufferUtils::ProcessEngine& process_engine) {
  frame_buffer_utils_ = vision::FrameBufferUtils::Create(process_engine);

  ASSIGN_OR_RETURN(input_specs_, vision::BuildInputImageTensorSpecs(
                                     *engine_->interpreter(),
                                     *engine_->metadata_extractor()));

  if (input_specs_.color_space != tflite::ColorSpaceType_RGB) {
    return tflite::support::CreateStatusWithPayload(
        absl::StatusCode::kUnimplemented,
        "ImagePreprocessor only supports RGB color space for now.");
  }

  return absl::OkStatus();
}

absl::Status ImagePreprocessor::Preprocess(const FrameBuffer& frame_buffer) {
  BoundingBox roi;
  roi.set_width(frame_buffer.dimension().width);
  roi.set_height(frame_buffer.dimension().height);
  return Preprocess(frame_buffer, roi);
}

absl::Status ImagePreprocessor::Preprocess(const FrameBuffer& frame_buffer,
                                           const BoundingBox& roi) {
  // Input data to be normalized (if needed) and used for inference. In most
  // cases, this is the result of image preprocessing. In case no image
  // preprocessing is needed (see below), this points to the input frame
  // buffer raw data.
  const uint8* input_data;
  size_t input_data_byte_size;

  // Optional buffers in case image preprocessing is needed.
  std::unique_ptr<FrameBuffer> preprocessed_frame_buffer;
  std::vector<uint8> preprocessed_data;

  if (IsImagePreprocessingNeeded(frame_buffer, roi) && !IsInputImageDynamic()) {
    // Preprocess input image to fit model requirements.
    // For now RGB is the only color space supported, which is ensured by
    // `InitInternal`.
    FrameBuffer::Dimension to_buffer_dimension = {input_specs_.image_width,
                                                  input_specs_.image_height};
    input_data_byte_size =
        GetBufferByteSize(to_buffer_dimension, FrameBuffer::Format::kRGB);
    preprocessed_data.resize(input_data_byte_size / sizeof(uint8), 0);
    input_data = preprocessed_data.data();

    FrameBuffer::Plane preprocessed_plane = {
        /*buffer=*/preprocessed_data.data(),
        /*stride=*/{input_specs_.image_width * kRgbPixelBytes, kRgbPixelBytes}};
    preprocessed_frame_buffer = FrameBuffer::Create(
        {preprocessed_plane}, to_buffer_dimension, FrameBuffer::Format::kRGB,
        FrameBuffer::Orientation::kTopLeft);

    RETURN_IF_ERROR(frame_buffer_utils_->Preprocess(
        frame_buffer, roi, preprocessed_frame_buffer.get()));
  } else {
    // Input frame buffer already targets model requirements: skip image
    // preprocessing. For RGB, the data is always stored in a single plane.

    // If dynamic, it will re-dim the entire graph as per the input.
    if (IsInputImageDynamic()) {
      // Determine if the input shape is resizable.
      const TfLiteIntArray* dims_signature = Tensor()->dims_signature;

      const bool height_mutable = dims_signature->data[1] == -1;
      const bool width_mutable = dims_signature->data[2] == -1;

      if (height_mutable || width_mutable) {
        const TfLiteIntArray* dims = Tensor()->dims;
        const Interpreter* interpreter = engine_->interpreter();

        // The expected BXHXWXD values of the model.
        const int expected_batch = Tensor()->dims->data[0];
        int expected_height = Tensor()->dims->data[1];
        int expected_width = Tensor()->dims->data[2];
        const int expected_depth = Tensor()->dims->data[3];

        // HXW of the input image.
        int image_height = frame_buffer.dimension().height;
        int image_width = frame_buffer.dimension().width;

        int height = height_mutable ? image_height : expected_height;
        int width = width_mutable ? image_width : expected_width;

        const std::vector<int> new_dims {expected_batch, height, width, expected_depth};

        interpreter->ResizeInputTensorStrict(0, new_dims);
      }
    }

    input_data = frame_buffer.plane(0).buffer;
    input_data_byte_size = frame_buffer.plane(0).stride.row_stride_bytes *
                           frame_buffer.dimension().height;
  }

  // Then normalize pixel data (if needed) and populate the input tensor.
  switch (input_specs_.tensor_type) {
    case kTfLiteUInt8:
      if (Tensor()->bytes != input_data_byte_size) {
        return tflite::support::CreateStatusWithPayload(
            absl::StatusCode::kInternal,
            "Size mismatch or unsupported padding bytes between pixel data "
            "and input tensor.");
      }
      // No normalization required: directly populate data.
      tflite::task::core::PopulateTensor(
          input_data, input_data_byte_size / sizeof(uint8), Tensor());
      break;
    case kTfLiteFloat32: {
      if (Tensor()->bytes / sizeof(float) !=
          input_data_byte_size / sizeof(uint8)) {
        return tflite::support::CreateStatusWithPayload(
            absl::StatusCode::kInternal,
            "Size mismatch or unsupported padding bytes between pixel data "
            "and input tensor.");
      }
      // Normalize and populate.
      float* normalized_input_data =
          tflite::task::core::AssertAndReturnTypedTensor<float>(Tensor());
      const tflite::task::vision::NormalizationOptions& normalization_options =
          input_specs_.normalization_options.value();
      for (int i = 0; i < normalization_options.num_values; i++) {
        if (std::abs(normalization_options.std_values[i]) <
            std::numeric_limits<float>::epsilon()) {
          return tflite::support::CreateStatusWithPayload(
              absl::StatusCode::kInternal,
              "NormalizationOptions.std_values can't be 0. Please check if the "
              "tensor metadata has been populated correctly.");
        }
      }
      if (normalization_options.num_values == 1) {
        float mean_value = normalization_options.mean_values[0];
        float inv_std_value = (1.0f / normalization_options.std_values[0]);
        for (size_t i = 0; i < input_data_byte_size / sizeof(uint8);
             i++, input_data++, normalized_input_data++) {
          *normalized_input_data =
              inv_std_value * (static_cast<float>(*input_data) - mean_value);
        }
      } else {
        std::array<float, 3> inv_std_values = {
            1.0f / normalization_options.std_values[0],
            1.0f / normalization_options.std_values[1],
            1.0f / normalization_options.std_values[2]};
        for (size_t i = 0; i < input_data_byte_size / sizeof(uint8);
             i++, input_data++, normalized_input_data++) {
          *normalized_input_data = inv_std_values[i % 3] *
                                   (static_cast<float>(*input_data) -
                                    normalization_options.mean_values[i % 3]);
        }
      }
      break;
    }
    case kTfLiteInt8:
      return tflite::support::CreateStatusWithPayload(
          absl::StatusCode::kUnimplemented,
          "kTfLiteInt8 input type is not implemented yet.");
    default:
      return tflite::support::CreateStatusWithPayload(
          absl::StatusCode::kInternal, "Unexpected input tensor type.");
  }

  return absl::OkStatus();
}

}  // namespace processor
}  // namespace task
}  // namespace tflite
<|endoftext|>